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  }