避坑
1.数组复制
Go语言中数据是值语义。 一个数组变量即表示整个数组,它并不是隐匿地指向第一个元素的指针,而是一个完整的值。当一个数组变量被赋值或被传递的时候,实际上会复制整个数组。如果数组较大的话,数组的赋值也会有较大的开销。
-- 避坑技巧 ---赋值或传递时,使用数组指针
2.添加切片元素可能会导致重新分配内存
切片(Slice)是一种简化版的动态数组。 由于数组的类型和操都不够灵活, 因此在Go代码中数组使用得并不多。而切片的使用却相当广泛,理解切片的原理和用法是Go程序员的必备技能。 因切片的长度不固定,所以切片的长度自然也就不能是类型的组成部分了。 我们用内置的泛型函数append(),可以在切片的尾部追加元素,不要注意的是,在容量不足的情况下,append()操作会导致重新分配内存,可能导致巨大的内存分配和复制数据的代码。 即使容量足够,依然需要用append()函数的返回值来更新切片本身,因为新切片的长度已经发生了变化。 在开头添加元素一般都会导致内存的重新分配,而且会导致已有的元素全部复制一次。因此从切片的开头添加元素的性能一般要比从尾部追加元素的性能差很多。
-- 避坑技巧 ---切片初始化时,尽量设定切片容量大小
2.Interface
Go官方文档中表示:interface本身是引用类型,即接口类型本身是指针类型。
当调用接口方法时,会自动对指针进行解引用。
首先明确接口是引用类型(指针),由于接口会自动对传递的指针进行解引用,所以当接口类型作为函数参数传递时,有以下规则: 当以指针接收器实现接口方法时,传递函数的参数必须为对象指针。 当以对象接收器实现接口方法时,传递函数的参数既可以是对象指针(指针会自动解引用),也可以是对象实例。
指向结构的指针和指向接口的指针是两回事,接口直接存放了结构的类型信息以及结构指针。在Go中,无法为实现了接口方法的struct生成指向接口的指针并调用接口方法。
3. nil
首先明确: nil是值而非类型。nil值只能赋值给slice、map、chan、interface和指针。
在Go中,任何类型都会有一个初始值。数值类型的初始值为0,slice、map、chan、interface和指针类型的初始值为nil,对于nil值的变量,我们可以简化理解为初始状态变量。
nil只是一个表示初始状态的值。
对于slice、map、chan、interface,当值为nil时,不具备可写性。
对于slice、map、chan类型的nil值变量,可以理解为可读不可写,只有通过make(new)创建的对象实例满足可写性。
4. defer
defer在声明时引用到的变量就已被“固定”下来
当defer在声明语句时引用到的变量就已被实时编译
注意defer直接声明语句,还是func
5. chan
从chan的实现源代码看到,其读写内部均加了锁,实际上在关闭chan时内部也是加锁了,所以实际应用中,多个coroutine同时读写chan时不需要加锁。
Last updated
Was this helpful?