《Go语言高级编程》:《Go语言高级编程》
一、语言基础
数组、切片、字符串
在go中,不同切片类型是无法强制类型转换的,但有时能提高代码性能。比如在64位系统上,需要对一个[]float64切片进行高速排序,我们可以将它强制转为[]int整数切片,然后以整数的方式进行排序(因为float64遵循IEEE754浮点数标准特性,当浮点数有序时对应的整数也必然是有序的)。
切片的解包语法:
var a []interface{}
fmt.Println(a...) // a... 即为解包
- 切片结构中有底层数组、长度、容量三个数据,其中底层数组是通过隐式指针传递的。因此切片作为函数参数传入时,用户可以对形参切片内容的修改会影响到外部的切片。但是如果涉及到对len、cap的更改,例如append,则会导致切片结构体的改变从而使得改变后的切片无法映射到原切片中,这也是为什么append需要返回一个新的切片的原因。总结为:切片作为参数传入时,如果只修改切片的内容,不修改切片的结构,那么函数内的修改会影响到外部的切片;但如果在函数内部修改了切片的结构,则不会影响外部的切片,除非函数返回修改后的切片将原切片覆盖掉。
函数、方法、接口
-
go语言总是从main包开始扫描,当发现有包导入时会先进入那个包,将那个包的初始化完成之后才回来继续完成main包的初始化。这过程中有两个知识点是新学到的:第一,一个file可以有多个init()函数,同一个package中多个init()的调用顺序是随机的,但一个file中多个init()的调用是顺序的;第二,整个初始化过程只有一个goroutine在工作,即主线程在工作,因此如果init()函数中使用go关键字启动了新的goroutine,也只会在main包初始化完成之后才会启动。
go语言本身不支持面向对象中的继承,但是可以通过在结构体中内置匿名的其他结构体来实现继承的效果。通过嵌入匿名的成员,可以使当前的结构体获得内嵌结构体的所有方法。一个很好的使用场景是:在结构体中嵌入匿名的锁。
type Cache struct {
m map[string]string
sync.RWMutex // 嵌入的匿名锁
}
func (c *Cache) Insert(key string, val string) {
c.Lock() // Cache结构体具有sync.RWMutex的方法
defer c.Unlock() // Cache结构体具有sync.RWMutex的方法
m[key] = val
}
func (c *Cache) GetValue(key string) string {
c. RLock() // Cache结构体具有sync.RWMutex的方法
defer c.RUnlock() // Cache结构体具有sync.RWMutex的方法
return m[key]
}
- 鸭子类型:只要走起来像鸭子、叫起来也像鸭子,就可以认为是鸭子。Go语言中的面向对象就是如此,如果一个对象只要看起来像是某种接口类型的实现,那么它就可以作为该接口类型使用。这种设计可以让你创建一个新的接口类型满足已经存在的具体类型却不用去破坏这些类型原有的定义;当我们使用的类型来自于不受我们控制的包时这种设计尤其灵活有用。