关于slice的困惑

1034992601 · · 799 次点击
没啥可困惑的, 把你的程序改一改就知道原因了. ```go func main() { old := make([]string, 0, 10) fmt.Printf("old address: %p\n", &old) old = append(old, "one") fmt.Printf("old address: %p\n", &old) add(old) fmt.Println(old) } func add(temp []string) { fmt.Printf("temp address: %p\n", &temp) temp = append(temp, "end") fmt.Printf("temp address: %p\n", &temp) fmt.Println(temp) } old address: 0xc000074020 old address: 0xc000074020 temp address: 0xc000074040 temp address: 0xc000074040 [one end] [one] ```
#3
更多评论
go中函数的参数是值传递的,所以将old通过参数传递到add的temp的时候,其实创建了新的切片对象,新切片的内容复制了old切片的内容。这两个切片共享底层数组(重点,底层数组不会复制)。切片对象包括一个指针,一个len,以及一个cap。所以这里使用%p打印old和temp,其实打印的应该是切片对象中的指针部分,两个切片中指针部分是相同的,因为他们指向同一个底层数组(我刚学golang,没看过源码,这部分是猜的,原理应该是这样的)。如果你打印&old和&temp,就会发行不同的,说明old和temp是两个不同的切片对象。当`old = append(old, "one")`后,你打印old 和 &old[0] 应该是一样的。 当在add中通过`temp = append(temp, "end")`,向切片添加元素后,可以认为底层数组的第二个元素被设置为了`end`。temp切片此时的len是2,包涵两个元素,`one`和`end`。但是main函数中,old切片的len还是1,所以add函数返回后,打印old,其只会包涵一个元素`one`。但此时底层数组的第二个元素其实已经是`end`了,只是因为old切片的长度,第二个元素不在old切片中。所以在add函数中,你可以返回temp切片,将其重新赋值给old,应该就能达到你想要的效果了。
#1
// 更正一些注释<br/> // 因为你在main函数里传递给add函数的应该是底层数组的地址,所以你的main函数无法得到正确的结果,可以通过返回值得到修改后的结果,或者修改形参,传变量的指针,以下代码两个函数都实现了你要的效果。<br/> package main import ( "fmt" ) func main() { old := make([]string, 0, 10) fmt.Printf("old address: %p\n", old) //你打印地址的方式也不对 old = append(old, "one") fmt.Printf("old address: %p\n", &old) //正确的方式 old = add(old) fmt.Println("old=", old) Add(&old) fmt.Println("调用Add后 old=", old) } // add 传递的应该是底层数组的地址,可通过返回值得到操作后的结果 func add(temp []string) []string { fmt.Printf("temp address1: %p\n", &temp) //传过来的地址跟main函数里不是同一地址 temp = append(temp, "end") fmt.Printf("temp address2: %p\n", &temp) //传过来的地址跟main函数里不是同一地址 fmt.Println(temp) return temp } // Add 传指针的方式,传递切片的指针 func Add(temp *[]string) { fmt.Printf("temp address1: %p\n", *&temp) //传过来的地址跟main函数里的一致 *temp = append(*temp, "end") fmt.Printf("temp address2: %p\n", *&temp) //传过来的地址跟main函数里的一致 fmt.Println(*temp) }
#2