接触go已经快两年了, 老是想把学过的东西写下来, 但是一直没能行动, 今天算开个头吧.

基础数据类型

在golang里有int(int、 int8、 int16、 int32、 int64、 uint、 uint8、 uint16、 uint32、 uint64)、 float(float32、 float64)、 struct、 array、 slice、 map、 interface{}等。 他们的介绍基本都知道就不说了, 我写点比较冷门的。

int和uint

int或者uint的长度是多少? 32位? 64位? 都有可能。 在golang中int的系统平台决定, 当系统是32位时(也就是GOARCH=x86)int或uint的长度为32位, 当系统为64位时(也就是GOARCH=amd64)int或uint的长度为64位。 所以int或uint的长度不是固定的, 而是由系统架构决定。 还有种说法是int的长度由计算机的cpu字长决定, 这种说明我认为不严谨, 在64位的系统上是可以运行32位的Go程序的, 在32位Go程序中int的长度肯定是32位。

传递类型

调用函数传递参数有两种情况,他们分别是:

  • 值传递
  • 指针传递

指针传递传递的是一个指针, 也就是原函数中变量在内存中的位置, 通过修改该位置内存上的内容会导致原函数中变量的内容也会改变。而值传递是在调用函数上创建一个和原函数参数变量一样的变量,再将原函数变量内容拷贝到调用函数新创建的变量中,调用函数中的变量与原函数变量值就是两个独立的变量互不影响。下面举例说明一下:

在go语言中map,slice,chan是指针传递而array、struct和其他一些基础数据类型(int,float等)下面我们来探究下slice。slice和array差不多,但是slice有array所不具备的特性,比如扩容等。下面我们先来看一个例子。

如果你的答案完全正确的话那么我要说的你应该都知道,可以跳过这一节内容了。如果不对,别怀疑,看下面分析。

首先array部分很好理解,array是值传递所以将a从main传递到arrayCall中时会在arraySlice的堆或者栈创建一个和main中a一模一样的变量并拷贝其值。因此arrayCall中的a和main中的a是两个完全独立的变量互不影响。

runtime/slice.go

我们可以看到slice是一个结构体,其中有array是一个指针指向一个数组的地址。len和cap分别描述slice的长度和容量,len()函数和cap函数对slice使用的时候其实就是读取这两个字段的值。array是一个指向数组的指针,这个数组用来存储slice中的实际数据。

make函数可以用来创建slice,其第一个参数是指定要创建的slice类型,第二个参数指定slice的长度,第三个参数指定slice的容量为可选参数若没有第三个参数则容量等于长度。make函数的创建slice的过程是先根据slice类型和容量创建一个该类型的数组其长度为容量值。再创建一个slice结构体,将其中的array字段指向刚刚创建的数组,并将len和cap字段赋值为make函数所接收到的值。make函数创建时cap可以大于len,表示为该slice预留了部分空间来扩容。

向slice插入新元素时就需要使用append函数,append函数分为两种情况。

cap-len>=需要插入的元素个数
cap-len<需要插入的元素个数原来的len+插入元素数量s[0]s[0]
原来的len+插入元素数量
sliceCall(s *[]int)

通过以上的分析再回头看看上面的程序应该都能理解了。

string与[]byte的黑魔法

在go中[]byte和string是可以进行互相装换的。但是go原生提供装换方法

这样转换最安全。但是由于[]byte和string进行转换时会重新创建一个新的对象,存在拷贝的性能损耗。下面介绍一种无拷贝的转换方法,这种方法是从雨痕那学到的,想看原文的可以看这里,我对原方法进行了简单改善增加了可读性:

下面看看性能提升怎么样,跑一下基准测试代码如下:

测试结果如下:

从上面结果可以看出效果还是不错的。在某些场景例如用base64来传输文件,go这边接收到一个base64的字符串而后续操作却需要用到[]byte切片。就可以使用该方法来处理不仅更快而且还能节省值拷贝带来的内存开销。

虽然这个方法看上去很棒但是却不是安全方法。需要注意string转换为slice后只能对该slice进行 读操作 不可进行修改操作,因为string只可读不可修改,尝试修改会触发 panic。还有就是unsafe.pointer不会创建GC的引用关系,如果超出了原string或slice的作用域有 被回收的风险。如果你对go的GC不了解,请谨慎使用。切记评估风险后谨慎使用。

文笔不好先写到这,下次研究一下interface。

原创作品,转载留名

参考资料

[雨痕 Go性能优化技巧 1/10] https://segmentfault.com/a/1190000005006351