快学 go 语言学习笔记
参考知乎专栏https://www.zhihu.com/column/quickgo
基础变量 var int = 3 在32位机器上占4字节,相当于int32类型 在64位机器上占8字节,相当于int64类型
分支与循环 if else, switch, for
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 # if else example func max(a int, b int) int { if a > b { return a } else { return b } } # switch example, 在python语言中使用多个else if来定义多个条件 func prize1(score int) string { switch score / 10 { case 0, 1, 2, 3, 4, 5: return "差" case 6, 7: return "及格" case 8: return "良" default: return "优" } } # for example, # 普通用法 func main() { for i := 0; i < 10; i++ { fmt.Println("hello world!") } } # 实现死循环 func main() { for { fmt.Println("hello world!") } }
数组 数组的长度是固定的,声明数组时需要指定数组长度,并且一旦声明后长度不能修改,值可以修改。
var arr1 [5]int var arr2 [6]int 数组长度也是类型的一部分,因此arr1和arr2属于不同的类型,传参时不能混用,也不能互相赋值。
1 2 3 4 5 6 7 8 9 10 func main() { var arr1 = [5]int{1,2,3,4,5} squares(&arr1) } func squares(arr *[6]int) { for i:=0; i<len(arr); i++ { arr[i] = arr[i] * arr[i] } }
上面代码会编译失败:cannot use &arr1 (type *[5]int) as type *[6]int in argument to squares
数组赋值时会分配新的内存地址,而不是引用。修改原数组并不会改变新数组,属于深拷贝。
1 2 3 4 5 6 7 8 9 10 11 12 func main() { var arr1 = [5]int{1,2,3,4,5} var arr2 [5]int = arr1 arr1[0] = 100 fmt.Println(arr1) fmt.Println(arr2) } ------ [100 2 3 4 5] [1 2 3 4 5]
对数组遍历的两种方式: 遍历下标 或者 使用range
1 2 3 4 5 6 7 8 9 for i:=0; i<len(arr); i++ { arr[i] = arr[i] * arr[i] } for i, v := range arr1 { fmt.Printf("index %d is %d\n",i, v) } for m := range arr1 { fmt.Printf("index %d is %d\n", m, arr1[m]) }
切片 切片变量包含三个域,分别是指向数组头元素的指针、已使用的切片长度、切片总容量。 append操作会填充剩余容量,如果容量不足需要分配一个更大容量的数组并将切片中的元素拷贝到新数组。
每次append都会生成一个新的切片变量,如果数组没有扩容,新旧切片变量共享一个数组。如果数组扩容,旧的切片变量还会指向原有数组,新的切片变量指向新的数组。 声明切片时可以不指定容量,默认分配空数组。
字典 声明字典并初始化
1 2 3 4 5 6 7 8 9 10 11 12 func main() { var dict1 map[int]string = make(map[int]string, 10) //可以指定长度 var dict2 = make(map[int]string) dict3 := map[int]string{} dict4 := map[int]string{ 90: "优秀", 80: "良", 60: "一般", 30: "差", } }
获取字典中的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 func main() { dict := map[int]string{ 90: "优秀", 80: "良", 60: "一般", 30: "差", } if res,ok := dict[90]; ok { //两个返回值,第二个返回值表示是否存在 fmt.Println("exist", res) } else { fmt.Println("not exist", res) } }
并发与安全 对于一些非线程安全的对象,如字典,在多线程操作时可以通过加入读写锁实现线程安全。
补充深拷贝和浅拷贝
B拷贝A 深拷贝:分配新的内存地址,将A的内容完全复制一份到新的内存空间去。修改A并不会导致B的改变。 浅拷贝:B只拿到了A的引用,所有无论修改A还是修改B,都会导致数据的更改。
go语言中的多数赋值操作为深拷贝(切片除外),除非显示的声明使用指针赋值,才是对原变量的浅拷贝。