1. 指针 指针不是内存地址。
内存地址是内存中每个字节单元的唯一编号,而指针则是一个实体。
指针会分配内存空间,相当于一个专门用来保存地址的整型变量。
GO指针,不支持加减运算和类型转换
可通过unsafe.Pointer将指针转换为uintptr后进行加减法运算,但可能会造成非法访问。
Pointer类似C语言中的void*万能指针,可用来转换指针类型。它能安全持有对象或对象成员,但uintptr不行。后者仅是一种特殊整型,并不引用目标对象,无法阻止垃圾回收器回收对象内存。
1.1 引用传递 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const MAX int = 3 func main () { var a int = 10 var b int = 20 fmt.Println(a, b) swap(&a, &b) fmt.Println(a, b) } func swap (x *int , y *int ) { var temp int temp = *x *x = *y *y = temp }
1.2 指针类型 1.2.1 三种指针:
1.2.2 unsafe.Pointer 作用
unsafe.Pointer 可以和 普通指针 进行互相转换
unsafe.Pointer 可以和 uintptr 进行相互转换
unsafe.Pointer 是桥梁,可以让任意类型的指针实现相互转换,也可以将任意类型的指针转换为uintptr进行指针运算
2. 切片 (Slice) 切片是对数组的抽象。数组长度固定,而切片长度不固定,可追加元素,被称为动态数组。
不是数组,但指向底层的数组
可现实变长数组
为引用类型
可直接创建(make)或从底层数组获取生成
len()
获取元素个数,cap()
获取容量
不支持比较操作(==, >, <)
1 2 3 4 5 type slice struct { array unsafe.Pointer len int cap int }
2.1 创建切片 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func main () { s1 := make ([]int , 3 , 5 ) s2 := make ([]int , 3 ) s3 := []int {10 , 20 , 3 : 30 } arr := [...]int {1 , 2 , 3 , 4 , 5 } s4 := arr[:] s5 := arr[2 :4 ] fmt.Println(s1, len (s1), cap (s1)) fmt.Println(s2, len (s2), cap (s2)) fmt.Println(s3, len (s3), cap (s3)) fmt.Println(s4, len (s4), cap (s4)) fmt.Println(s5, len (s5), cap (s5)) }
2.2 空切片 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func main () { var s1 []int s2 := []int {} fmt.Println(s1==nil , s2==nil ) fmt.Printf("a: %#v\n" , (*reflect.SliceHeader)(unsafe.Pointer(&s1))) fmt.Printf("b: %#v\n" , (*reflect.SliceHeader)(unsafe.Pointer(&s2))) fmt.Printf("Size of a: %d\n" , unsafe.Sizeof(s1)) fmt.Printf("Size of a: %d\n" , unsafe.Sizeof(s2)) }
2.3 复制数据 允许指向同一底层数组,允许目标区间重叠。最终所复制长度以较短的切片长度(len)为准
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func main () { s1 := []int {1 , 2 , 3 , 4 , 5 , 6 } s2 := []int {7 , 8 , 9 } copy (s1, s2) fmt.Println(s1) fmt.Println(s2) s3 := []byte {'a' , 'b' , 'c' } s4 := []byte {'d' , 'e' , 'f' , 'g' , 'h' } copy (s3, s4) fmt.Println(s3) fmt.Println(s4) }
2.4 扩容数据 1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { s1 := make ([]int , 3 , 6 ) fmt.Printf("%v %p\n" , s1, s1) fmt.Println(len (s1), cap (s1)) s1 = append (s1, 1 , 2 , 3 ) fmt.Printf("%v %p\n" , s1, s1) fmt.Println(len (s1), cap (s1)) s1 = append (s1, 4 ) fmt.Printf("%v %p\n" , s1, s1) fmt.Println(len (s1), cap (s1)) }
Slice坑 :slice虽然是引用,但可能被重新分配内存
1 2 3 4 5 6 7 8 9 10 11 func foo (s []int ) { s = append (s, 1 ) } func main () { s := make ([]int , 0 ) fmt.Println(s) foo(s) fmt.Println(s) }
3. 集合 (map) make([keyType]valueType, cap)
3.1 基本操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func main () { m := map [string ]int { "a" : 1 , "b" : 2 , } m["a" ] = 5 m["c" ] = 8 if v, ok := m["d" ]; ok { println (v) } delete (m, "d" ) for k, v := range m { println (k, ":" , v, " " ) } }
3.2 多层map嵌套 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func main () { m := make (map [int ]map [int ]string ) m[1 ] = make (map [int ]string ) m[1 ][1 ] = "OK" fmt.Println(m) a, ok := m[2 ][1 ] fmt.Println(a, ok) if !ok { m[2 ] = make (map [int ]string ) } fmt.Println(m) }
3.3 不支持修改成员值(struct或array) 字典被设计成“not addressable”,故不能直接修改value成员(结构或数组)
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 func main () { m := map [int ]user{ 1 : user{"Jack" , 23 }, 2 : user{"Tom" , 22 }, } jack := m[1 ] jack.age++ m[1 ] = jack fmt.Println(m) m2 := map [int ]*user{ 1 : &user{"Jack" , 23 }, 2 : &user{"Tom" , 22 }, } m2[1 ].age++ fmt.Println(m2[1 ]) } type user struct { name string age int }
1 2 3 4 5 6 7 8 9 10 11 12 13 func main () { m := map [string ][2 ]int { "a" : {1 , 2 }, } a := m["a" ] fmt.Printf("%p, %v\n" , &a, a) s := a[:] fmt.Printf("%p, %v\n" , &s, s) }
3.4 map间接排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 func main () { m := map [int ]string {2 : "b" , 5 : "e" , 1 : "a" , 3 : "c" , 4 : "d" } s := make ([]int , len (m)) i := 0 for k, _ := range m { s[i] = k i++ } fmt.Println(s) sort.Ints(s) fmt.Println(s) for _, v := range s { fmt.Println(m[v]) } }
3.5 并发读写字典 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 func main () { var lock sync.RWMutex m := make (map [string ]int ) go func () { for { lock.Lock() m["a" ] += 1 lock.Unlock() time.Sleep(time.Microsecond) } }() go func () { for { lock.RLock() _ = m["b" ] lock.RUnlock() time.Sleep(time.Microsecond) } }() select {} }
4. range 用于for循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。
4.1 示例:遍历map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func main () { sm := make ([]map [int ]string , 3 ) for _, v := range sm { v = make (map [int ]string ) v[1 ] = "OK" fmt.Println(v) } fmt.Println(sm) for i := range sm { sm[i] = make (map [int ]string ) sm[i][1 ] = "OK" fmt.Println(sm[i]) } fmt.Println(sm) }
4.2 示例:遍历slice 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func main () { nums := []int {2 , 3 , 4 } sum := 0 for _, num := range nums { sum += num } fmt.Println("sum:" , sum) for i, num := range nums { if num == 3 { fmt.Println("index:" , i) } } for i, c := range "go语言" { fmt.Println(i, c) } }