github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/prepare/20_trap/dirtyslice/main.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 ) 7 8 func main() { 9 10 //testAppend() 11 //testRet() 12 //testFunParam() 13 14 //testAppend2() 15 16 //testAppend3() 17 18 // 不会发生panic 19 v := []int{1, 2, 3} 20 for i := range v { 21 v = append(v, i) 22 } 23 24 fmt.Println(v) 25 } 26 27 func testAppend3() { 28 slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} 29 s1 := slice[2:5] // len=5-2=3 cap=len(slice)-2=8 30 s2 := s1[2:6:7] // len=6-2=4 cap=7-2=5 31 32 s2 = append(s2, 100) 33 // s1[2] = 20 此处修改会s2中首个元素位置的值 34 s2 = append(s2, 200) 35 36 s1[2] = 20 37 38 fmt.Println(s1) 39 fmt.Println(s2) 40 fmt.Println(slice) 41 42 cap := 4 43 fmt.Println(uintptr(cap)) 44 45 } 46 47 func testAppend2() { 48 path := []byte("AAAA/BBBBBBBBB") 49 sepIndex := bytes.IndexByte(path, '/') 50 // 两个文件夹的slice都潜在的引用了同一个原始的路径slice 51 //dir1 := path[:sepIndex] 52 53 // 修改: 54 // 完整的slice表达式中的额外参数可以控制新的slice的容量。 55 // 现在在那个slice后添加元素将会触发一个新的buffer分配,而不是覆盖第二个slice中的数据 56 dir1 := path[:sepIndex:sepIndex] //full slice expression 57 58 dir2 := path[sepIndex+1:] 59 fmt.Println("dir1 =>", string(dir1), cap(dir1)) //prints: dir1 => AAAA 60 fmt.Println("dir2 =>", string(dir2)) //prints: dir2 => BBBBBBBBB 61 62 dir1 = append(dir1, "suffix"...) 63 path = bytes.Join([][]byte{dir1, dir2}, []byte{'/'}) 64 65 fmt.Println("dir1 =>", string(dir1)) //prints: dir1 => AAAAsuffix 66 fmt.Println("dir2 =>", string(dir2)) //prints: dir2 => uffixBBBB (not ok) 67 68 fmt.Println("new path =>", string(path)) 69 } 70 71 // 测试函数参数时切片 72 func testFunParam() { 73 raw := []string{"线性代数", "统计", "概率", "微积分"} 74 fmt.Printf("before raw:%v %p %v \n", raw, &raw[0], cap(raw)) 75 //sliceParam(raw) 76 sliceParamPrt(&raw) 77 fmt.Printf("after raw:%v %p %v \n", raw, &raw[0], cap(raw)) 78 79 } 80 81 func sliceParamPrt(math *[]string) { // 会将 cap len *prt的信息一并传过去 82 fmt.Printf("math:%v %p %v \n", *math, &(*math)[0], cap(*math)) 83 //ns := append(*math, "三角") // 此时创建新底层数组 84 //fmt.Printf("ns:%v %p %v \n", ns, &ns[0], cap(ns)) 85 86 *math = append(*math, "三角") // 此时创建新底层数组, (注意是指针的重新赋值,会导致调用者的 raw指向也改变) 87 fmt.Printf("math:%v %p %v \n", *math, &(*math)[0], cap(*math)) 88 } 89 90 func sliceParam(math []string) { 91 fmt.Printf("math:%v %p %v \n", math, &math[0], cap(math)) 92 math = append(math, "三角") // 此时创建新底层数组 93 fmt.Printf("math:%v %p %v \n", math, &math[0], cap(math)) 94 } 95 96 // 测试返回值对底层数组的改变 97 func testRet() { 98 // 返回回来的切片 都是共享底层数组的 99 ret := getSlice() 100 ns := ret 101 ns2 := append(ret, "三角") 102 fmt.Printf("ns:%v %p %d \n", ns, &ns[0], cap(ns)) 103 fmt.Printf("ns2:%v %p %d \n", ns2, &ns2[0], cap(ns2)) 104 105 ret = append(ret, "几何") 106 fmt.Printf("ns2:%v %p %d \n", ns2, &ns2[0], cap(ns2)) 107 fmt.Printf("ret:%v %p %d \n", ret, &ret[0], cap(ret)) 108 109 } 110 111 func getSlice() []string { 112 raw := []string{"线性代数", "统计", "概率", "微积分"} 113 fmt.Printf("raw: %p\n", &raw[0]) 114 ret := raw[:3] 115 return ret 116 } 117 118 // 测试 append, 对底层数组的改变 119 func testAppend() { 120 raw := []string{"线性代数", "统计", "概率", "微积分"} 121 sras := raw[:2] 122 ns := append(sras, "机器学习") // 这里底层会创建新的数组 123 124 fmt.Printf("ns:%v %p\n", ns, &ns[0]) 125 fmt.Printf("raw:%v %p\n", raw, &raw[0]) 126 127 raw = append(ns, "均值不等式") // 将 raw指向了 ns的数组, 此时他们两个切片共享一个底层数组 128 ns[0] = "golang" 129 130 fmt.Println() 131 fmt.Printf("ns:%v %p\n", ns, &ns[0]) 132 fmt.Printf("raw:%v %p\n", raw, &raw[0]) 133 134 fmt.Println() 135 ns = append(ns, "复数") 136 fmt.Printf("ns:%v %p\n", ns, &ns[0]) 137 fmt.Printf("raw:%v %p\n", raw, &raw[0]) 138 }