1. 引用传递时append会复制生成新的指针
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 \n", 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\n", subArray, a, subArray2,subArray3, &subArray[0], &a[0], &subArray2[0],&subArray3[0])
//扩容测试
fmt.Printf("%v %v \n", len(s), cap(s))
s=append(s, 1)
fmt.Printf("%v %v \n", len(s), cap(s))
s=append(s, 1)
fmt.Printf("%v %v \n", 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 \n", 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 \n", 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。
参考 : https://tip.golang.org/doc/go1.12#fmt
解决: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])
}
}