1. 引用传递时append会复制生成新的指针
package main
import ( "fmt" ) func w(s []int )[]int{ fmt.Printf("in w %v %#v ",s ,&s[0] )
//append后s指定新复制的内存指针了,不再指向原来的内存 s=append(s, 0) fmt.Printf("after append w %v %#v ",s ,&s[0] ) return s } func main() { s:=[]int{1} fmt.Printf("out of w %v %#v ",s ,&s[0] ) s2:=w(s)
//原来的指针s的内容依然在内存中,而不是被覆盖/GC了 fmt.Printf("after w %v %#v %v %#v ",s ,&s[0],s2 ,&s2[0] ) }
output:
out of w [1] (*int)(0x40e020) in w [1] (*int)(0x40e020) after append w [1 0] (*int)(0x40e040) after w [1] (*int)(0x40e020) [1 0] (*int)(0x40e040)
2. 空值append
package main import ( "fmt" ) func main() { s:=[][]int{} //使用...更加方便,还不会导致塞入空值 fmt.Println("Hello, playground", append(s, [][]int{}... ), append(s, []int{} )) }
output:
Hello, playground [] [[]]
3. 数组、slice、切片的雷!
package main import ( "fmt" "reflect" ) func main() { //固定长度是array类型,可以覆盖成员,但不能修改长度,即不能append a := [4]int{1,2} a[0]=9 //没设置长度是slice类型,即动态或不定长数组, 也能覆盖成员,也修改长度,即支持append s := []int{1,2} //s[1:len(s):cap(s)] 等效 s[1:len(s)] s[0]=9 //注意下村是:左开(含左边元素),右闭(不含右边元素) fmt.Printf("%#v %#v %v %v %#v %#v %#v ", a ,s, reflect.TypeOf(a).Kind(), reflect.TypeOf(s).Kind(), a[1:len(a)], s[1:len(s):cap(s)],s[1:len(s)], ) //subslice切片 //切片,也叫subslice,是一块基于父slice的投影 subArray:=a[0:2] //报错:invalid slice index: 3 > 2, 即len不能超过cap //subArray2:=subArray[0:3:2] subArray2:=subArray[0:1:2] //报错:index out of range [1] with length 1 //subArray2[1]=222 //报错:index out of range [1] with length 1,len+offset>父slice的cap ,投影不能超出父slice的cap区域 //subArray3:=subArray2[1:2:2] subArray3:=subArray2[0:] //切片是指定父slice的指针,所以会修改父slice,使用时一定要小心!!! subArray3[0]=222 //subArray虽然是新变量名,但实际指定同一个内存地址 fmt.Printf("subslice %#v %#v %#v %#v %v %v %v %v ", subArray, a, subArray2,subArray3, &subArray[0], &a[0], &subArray2[0],&subArray3[0]) //扩容测试 fmt.Printf("%v %v ", len(s), cap(s)) s=append(s, 1) fmt.Printf("%v %v ", len(s), cap(s)) s=append(s, 1) fmt.Printf("%v %v ", len(s), cap(s)) //tmp:=[8]int{} //错误:cannot use tmp (type [8]int) as type []int in append //正确玩法: //不能用Printf中有unicode,否则会 format %扩 has unknown verb 扩 fmt.Println("len增加且超过cap时,若<=1024,以100%扩容 ") s=[]int{} i:=64 for i>=0 { fmt.Printf("%v %v ", len(s), cap(s)) s=append(s,1) i-=1 } fmt.Println("len增加且超过cap>1024时,否则以大约25%扩容,注意是大约") //大约25%扩容详细参考: https://juejin.im/post/5ca4239ef265da30807fea48 i=1028 s=[]int{} for i>=0 { s=append(s,1) i-=1 if i%100==0{ fmt.Printf("%v %v ", len(s), cap(s)) } } }
output:
[4]int{9, 2, 0, 0} []int{9, 2} array slice []int{2, 0, 0} []int{2} []int{2} subslice []int{222, 2} [4]int{222, 2, 0, 0} []int{222} []int{222} 0x40e020 0x40e020 0x40e020 0x40e020 2 2 3 4 4 4 len增加且超过cap时,若<=1024,以100%扩容 0 0 1 2 2 2 3 4 4 4 5 8 6 8 7 8 8 8 9 16 10 16 11 16 12 16 13 16 14 16 15 16 16 16 17 32 18 32 19 32 20 32 21 32 22 32 23 32 24 32 25 32 26 32 27 32 28 32 29 32 30 32 31 32 32 32 33 64 34 64 35 64 36 64 37 64 38 64 39 64 40 64 41 64 42 64 43 64 44 64 45 64 46 64 47 64 48 64 49 64 50 64 51 64 52 64 53 64 54 64 55 64 56 64 57 64 58 64 59 64 60 64 61 64 62 64 63 64 64 64 len增加且超过cap>1024时,否则以大约25%扩容,注意是大约 28 32 128 128 228 256 328 512 428 512 528 1024 628 1024 728 1024 828 1024 928 1024 1028 1344
4. 字符串不能随意for
package main import ( "fmt" ) func main() { s:="abc中国人" fmt.Println("for len是逐个unicode,也叫rune") for k,v:=range s { fmt.Println(k, string(v)) } fmt.Println("for len是逐个字节, 非ascii就会乱") for i:=0;i<len(s);i++{ fmt.Println(i, string(s[i])) } fmt.Println("正确用法:") //for len是逐个字节 u:=[]rune(s) l:=len(u) for i:=0;i<l;i++{ fmt.Println(i, string(u[i])) } }
output:
for len是逐个unicode,也叫rune 0 a 1 b 2 c 3 中 6 国 9 人 for len是逐个字节, 非ascii就会乱 0 a 1 b 2 c 3 ä 4 ¸ 5 6 å 7 8 ½ 9 ä 10 º 11 º 正确用法: 0 a 1 b 2 c 3 中 4 国 5 人
4. map是无序的
package main import ( "fmt" ) func main() { m:=map[string]string{ "cc":"CC", "aa":"AA", "bb":"BB", } for k,v:=range(m){ fmt.Println(k,v) } fmt.Println("") for k,v:=range(m){ fmt.Println(k,v) } fmt.Println("") for k,v:=range(m){ fmt.Println(k,v) } fmt.Println("") // sort 'string' key in increasing order fmt.Println("fix : ") for k,v:=range(m){ fmt.Println(k,v) } }
output:
cc CC aa AA bb BB cc CC aa AA bb BB bb BB cc CC aa AA fix : cc CC aa AA bb BB
原因:
根据Go规范, map上的迭代顺序是不确定的,并且在程序运行之间可能会有所不同。实际上,不仅它是不确定的,而且实际上是有意随机化的。这是因为它曾经是可预测的,并且Go语言开发人员不希望人们依赖未指定的行为,所以他们有意地将其随机化,因此不可能依赖此行为。维护原插入顺序需要更多内存和cpu操作,Go设计简洁,无序意味着性能更佳,且不是所有地方都需要顺序。想排序或者按插入顺序,很容易自行实现。在Go 1.12+中,您只需打印一个map,它将自动按键排序。之所以添加它,是因为它可以轻松测试map。
原文:https://blog.golang.org/go-maps-in-action 中 When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. If you require a stable iteration order you must maintain a separate data structure that specifies that order。
解决:package mainimport ( "fmt" "sort"
) //按插入的顺序 type RawSortedMap struct {
//map key类型不能是slices, maps, and functions; these types cannot be compared using==
, and may not be used as map keys. m map[string]interface{} keys []interface{} } func NewRawSortedMap(cap int)RawSortedMap{ m := make(map[string]interface{}, cap) keys:=make([]interface{}, cap) n:=RawSortedMap{m, keys} return n } func (r *RawSortedMap) Set(k string, v interface{}) { //通过k 快速查找
//map不能同时read 和write,否则请加sync.RWMutex锁或者CAS .
r.m[k] = len(r.m) //通过keys数组快速遍历 r.keys = append(r.keys, v) } func main() { m := make(map[int]string) m[1] = "a" m[2] = "c" m[0] = "b" // To store the keys in slice in sorted order var keys []int for k := range m { keys = append(keys, k) } //按数字大小的顺序 sort.Ints(keys) //按字母的顺序 //sort.Strings(keys) // To perform the opertion you want for _, k := range keys { fmt.Println("Key:", k, "Value:", m[k]) } }