C++引用的秘密

0. 一个错误的概念

1
2
3
4
5
6
int main() {
int a = 111;
int &b = a;
b = 222;
std::cout<<&a<<&b;
}

我们能看到这里输出的两个值相同。

  • 错误1:

    很多人认为这里的b就是a,a就是b,a和b的地址是一样的,如下图。

    但是笔者要说,其实这个概念是有问题的,a是a,b是b,a和b并不是同一个地址。

Read More

Springfox使用

1. 对List不能很好的支持

1.1. 核心代码

代码中写的是数组

1
2
3
4
5
/**
* 用户
*/
@ApiModelProperty(value = "用户",example = "hellowang")
private List<String> user;

1.2. 问题详情

在swagger页面展示的例子是字符串

1
2
3
{
"user": "hellowang"
}

1.3. 问题讨论

Stackoverflow

Github

1.4. 解决方案

springfox-collection-example-plugin

Go入门-常见陷阱

1. Go 的指针

Go的指针和C的指针很类似,这也是Go被归类于C类语言的原因,Go的指针不支持偏移运算,即不能向C一样让指针+1,-1。

1.1. 正常使用

先来看第一个,符号&即可取到对象的地址。

1
2
3
4
5
6
7
func sample1() {
arr1 := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

fmt.Println(arr1)

fmt.Println(&arr1)
}
1
2
[0 1 2 3 4 5 6 7 8 9]
&[0 1 2 3 4 5 6 7 8 9]

1.2. for循环问题

下面的输出全是9,因为for循环的value是共用一个地址的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func sample2() {
arr1 := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

mp := map[int]*int{}

for i, value := range arr1 {
mp[i] = &value
}


for i, _ := range arr1 {
fmt.Println(*mp[i])
}
}

2. Go 的 new 和 make

参考

new 只分配内存,make不仅分配内存还初始化对象。

slice、chan、map一般可以使用make初始化。

Go进阶-Module

1. Module使用

在文章Go入门-Go语言从入门到进阶实战中,我们介绍了GO项目的结构,但是没有解释其中的一个文件go.mod, 这其实是模块的意思。在go.mod中可以引入go的依赖。

1
2
3
4
5
6
require (
github.com/golang/mock v1.4.4
github.com/golang/protobuf v1.4.3
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/stretchr/testify v1.6.1
)

这里简单介绍一下,注意到这里是库名加版本号。当我们引入了依赖管理以后,就可以在自己的项目中直接import三方包了。

2. Module 的历史

Go modules 是 Go 语言的依赖解决方案,发布于 Go1.11,Go1.14 上已经明确建议生产上使用了

  • 一开始go发布的时候是没有包管理的

  • go get命令会根据路径,把相应的模块获取并保存在$GOPATH/src

  • 也没有版本的概念,master 就代表稳定的版本

原文: 😊

在Go Module出现以前,我们使用Go Get获取库,库会直接下载到GOPATH目录的src文件夹下,很好用但是有一个问题-版本兼容问题。

当两个库依赖分别同一个库的v1和v2版本的时候,如果v1和v2不兼容,那么会导致这两个库无法同时使用。

后来官方采用了vgo方案来解决GO的依赖管理问题,也就是现在的Go modules。

Read More

Go入门-Effective-Go

1. Effective GO

https://github.com/bingohuang/effective-go-zh-en

2. 格式化

在最开始学习GO的时候,写了几篇Blog,发现代码里面的对齐都是TAB,这让我很困惑,知道现在才知道,GO语言,默认使用TAB进行对齐。

当然GO还有自己的空格规则x<<8 + y<<16,向这份代码,我们根据空格就能知道计算的优先级了。

3. 注释

3.1. 包注释

Go语言要求package语句前加上注释,来介绍整个包,如果package包含多个文件,则只需要在其中一个文件中标注即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
Package regexp implements a simple library for regular expressions.

The syntax of the regular expressions accepted is:

regexp:
concatenation { '|' concatenation }
concatenation:
{ closure }
closure:
term [ '*' | '+' | '?' ]
term:
'^'
'$'
'.'
character
'[' [ '^' ] character-ranges ']'
'(' regexp ')'
*/
package regexp

Read More

Go进阶-Web框架

0. 前言

简单介绍Beego和Gin,水一水文章。

1.1. 安装Beego库

1
go get github.com/astaxie/beego

同时安装Bee工具

1
go get github.com/beego/bee

看到如下内容代表安装成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
s@HELLOWANG-MB1 ~ % go get github.com/astaxie/beego
go: downloading github.com/astaxie/beego v1.12.3
go: downloading github.com/prometheus/client_golang v1.7.0
go: downloading github.com/hashicorp/golang-lru v0.5.4
go: downloading golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
go: downloading github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644
go: downloading github.com/prometheus/common v0.10.0
go: downloading github.com/prometheus/client_model v0.2.0
go: downloading github.com/prometheus/procfs v0.1.3
go: downloading github.com/beorn7/perks v1.0.1
go: downloading golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1
go: downloading github.com/cespare/xxhash/v2 v2.1.1
go: downloading github.com/golang/protobuf v1.4.2
go: downloading github.com/matttproud/golang_protobuf_extensions v1.0.1
go: downloading google.golang.org/protobuf v1.23.0
s@HELLOWANG-MB1 ~ % go get github.com/beego/bee
go: downloading github.com/beego/bee v1.12.3
go: downloading github.com/gadelkareem/delve v1.4.2-0.20200619175259-dcd01330766f
go: downloading github.com/gorilla/websocket v1.4.2
go: downloading github.com/lib/pq v1.7.0
go: downloading github.com/flosch/pongo2 v0.0.0-20200529170236-5abacdfa4915
go: downloading github.com/pelletier/go-toml v1.2.0
go: downloading github.com/smartwalle/pongo2render v1.0.1
go: downloading github.com/spf13/viper v1.7.0
go: downloading github.com/astaxie/beego v1.12.1
go: downloading github.com/hashicorp/hcl v1.0.0
go: downloading github.com/magiconair/properties v1.8.1
go: downloading github.com/spf13/afero v1.1.2
go: downloading github.com/spf13/cast v1.3.0
go: downloading github.com/spf13/jwalterweatherman v1.0.0
go: downloading github.com/spf13/pflag v1.0.3
go: downloading github.com/subosito/gotenv v1.2.0
go: downloading gopkg.in/ini.v1 v1.51.0
go: downloading golang.org/x/text v0.3.2
go: downloading github.com/sirupsen/logrus v1.6.0
go: downloading github.com/cosiner/argv v0.1.0
go: downloading github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b
go: downloading github.com/mattn/go-colorable v0.0.9
go: downloading github.com/mattn/go-isatty v0.0.3
go: downloading golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4
go: downloading go.starlark.net v0.0.0-20190702223751-32f345186213
go: downloading github.com/konsorten/go-windows-terminal-sequences v1.0.3
go get: installing executables with 'go get' in module mode is deprecated.
Use 'go install pkg@version' instead.
For more information, see https://golang.org/doc/go-get-install-deprecation
or run 'go help get' or 'go help install'.

Read More

双数组字典树

0. 前置知识

需要提前有字典树的知识

1. 双数组字典树介绍

双数组字典树英文名为DoubleArrayTrie,他的特点就是使用两个数组来表示一颗字典树,这里有比较有趣了,两个数组是怎么表达出字典树的呢?

2. 双数组介绍

顾名思义,有两个数组,一个是base,另一个是check。

首先介绍数组的下标,数组的下标代表字典树上节点的编号,一个下标对应一个节点。

其实base数组的作用是用来记录一个基础值,这个值可以是随机值,只要不产生冲突就可以了,所以这个值可以用随机数算法获取,当然这样效率不高,高效的做法应该是使用指针枚举技术,ok,现在你已经明白了,base数组是一个不产生冲突的随机数组。

最后,check数组,check数组与base数组相互照应,如果base[i]=check[j] 则说明j是i的儿子,而且i到j的边权恰好为j-base[i],也可以写作j-check[j]好好理解这句话

从另一个方面而言,双数组字典树的base数组,应该是一个指针数组,他指向了一个长度为字符集大小的数组的首地址,而check数组是一种hash碰撞思路,由于base数组疯狂指向自己,导致产生了很多碰撞,但是由于字典树是一个稀疏图,导致儿子节点指针利用率低,所以base数组疯狂复用这段空间,最后必须要依赖check来解决冲突,

双数组字典树相比于传统字典树,仅仅只在内存方面于增删改查占有优势,但是唯一不好的地方就是删和改会导致base数组内存分裂,难以回收,删和改如果占大头,那么传统字典树的内存效率更高

由于搜索领域几乎不涉及到删和改,所以这个数据结构很nice,字符集多大,就节省了多少倍的空间

数据结构很棒,但是在现在这个内存不值钱的时代,这些指针的储存用hashmap直接无脑顶掉,空间占用也高不了多少,hashmap顶多浪费两倍空间

两倍的空间算不上啥,除非这是唯一的优化点,否则不会优化到这个数据结构上来

Read More

Go入门-Go语言从入门到进阶实战

1. 开始学习Go

从一本书开始,这本书叫做《Go语言从入门到进阶实战(视频教学版)》,当然这篇Blog并不是所有的内容都来自这本书,毕竟书中也有不足之处。

2. Hello World

学啥语言的第一步都是Hello World, 第一步是搭建开发环境,直接下载Goland,创建一个新的工程,点击create

Read More

Go进阶-协程的本质与CPU的争夺

1. 从协程谈起

很多语言都支持协程,那什么是协程,和线程进程有什么区别呢?这里推荐一篇Blog,笔者直接提取其中最重要的部分

进程、线程 和 协程 之间概念的区别

  对于 进程、线程,都是有内核进行调度,有 CPU 时间片的概念,进行 抢占式调度(有多种调度算法)

  对于 协程(用户级线程),这是对内核透明的,也就是系统并不知道有协程的存在,是完全由用户自己的程序进行调度的,因为是由用户程序自己控制,那么就很难像抢占式调度那样做到强制的 CPU 控制权切换到其他进程/线程,通常只能进行 协作式调度,需要协程自己主动把控制权转让出去之后,其他协程才能被执行到。

 goroutine 和协程区别

  本质上,goroutine 就是协程。 不同的是,Golang 在 runtime、系统调用等多方面对 goroutine 调度进行了封装和处理,当遇到长时间执行或者进行系统调用时,会主动把当前 goroutine 的CPU (P) 转让出去,让其他 goroutine 能被调度并执行,也就是 Golang 从语言层面支持了协程。Golang 的一大特色就是从语言层面原生支持协程,在函数或者方法前面加 go关键字就可创建一个协程。

操作系统是不知道协程的,那么应用层如何实现协程呢?下面给一些伪代码

1
2
3
4
5
6
7
8
不断循环:
从任务队列获取任务
执行任务,如果任务运行结束:
进行下一轮循环(continue)
如果任务运行时进入阻塞状态:
把当前任务放入队列尾部(挂起)
如果任务主动释放CPU:
把当前任务放入队列尾部(挂起)

我们可以看到,其实这里正在执行的任务就是协程,这样的线程模型,他的CPU利用率非常高,他的协程切换代价非常低,几乎只需要入队出队而已。

但是这样的模型有一个很大的缺点,那就是CPU的公平性,如果一个协程迟迟不退出,且不进行系统调用,也不主动释放CPU,那么,这个协程将造成队头阻塞现象。

Read More