golang中切片slice的引用和地址问题

ddxx11223 · 2017-09-26 03:32:16 · 4552 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2017-09-26 03:32:16 的主题,其中的信息可能已经有所发展或是发生改变。

func main() {

    var t=make([]int,0,10)
    var s=make([]int,0,10)

    fmt.Printf("addr:%p \t\tlen:%v content:%v\n",t,len(t),t);
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n",s,len(s),s);

result: addr:0x1044c030 len:0 content:[] addr:0x1044c060 len:0 content:[]

    t =append(s,1,2,3,4)
    fmt.Println(t)
    fmt.Println(s)

result: [1 2 3 4] []

    fmt.Printf("addr:%p \t\tlen:%v content:%v\n",t,len(t),t);
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n",s,len(s),s);     }

result: addr:0x1044c060 len:4 content:[1 2 3 4] addr:0x1044c060 len:0 content:[]

一开始两个切片地址不同,可以理解。 后面我进行append,容量足够的情况下,切片地址是不会变的,那为什么s和t的地址是一样的,它们的内容却不一样? 还有,这里发帖怎么换行?新来的,请多多关照


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

4552 次点击  
加入收藏 微博
9 回复  |  直到 2017-09-28 01:23:42
specita
specita · #1 · 8年之前
fmt.Printf("addr:%p \t\tlen:%v content:%v\n",&t,len(t),t)
fmt.Printf("addr:%p \t\tlen:%v content:%v\n",&s,len(s),s)
Cynhard
Cynhard · #2 · 8年之前

切片是基于数组的。可以把切片简单的理解为数组中的一段,它保留了指向数组中某个元素(可以不是第一个元素)的指针,以及它本身的长度(也就是切片的大小)。var s=make([]int,0,10)这条语句创建了一个长度为10的数组,并在该数组之上建立了一个切片s,该切片保留指向数组第一个元素的指针,以及它的长度(0)。t = append(s,1,2,3,4) 这条语句向 s 指向的数组中追加了 4 个元素(注意这里 s 并没有变化,它的长度仍然是0,仅仅是底层数组变了)并返回新的切片(指向数组的第一个元素,长度为4)赋值给 t 。现在 s 和 t 都指向同一个数组的第一个元素,因此他们的地址是相同的。而 s 的长度是0,t 的长度是4. 可以参考go的文档:go doc builtin.make 以及 go doc builtin.append

javasgl
javasgl · #3 · 8年之前
CynhardCynhard #2 回复

切片是基于数组的。可以把切片简单的理解为数组中的一段,它保留了指向数组中某个元素(可以不是第一个元素)的指针,以及它本身的长度(也就是切片的大小)。`var s=make([]int,0,10)`这条语句创建了一个长度为10的数组,并在该数组之上建立了一个切片s,该切片保留指向数组第一个元素的指针,以及它的长度(0)。`t = append(s,1,2,3,4)` 这条语句向 s 指向的数组中追加了 4 个元素(注意这里 s 并没有变化,它的长度仍然是0,仅仅是底层数组变了)并返回新的切片(指向数组的第一个元素,长度为4)赋值给 t 。现在 s 和 t 都指向同一个数组的第一个元素,因此他们的地址是相同的。而 s 的长度是0,t 的长度是4. 可以参考go的文档:go doc builtin.make 以及 go doc builtin.append

当执行append的内容超出底层数组长度时,t=append(s,[]int{1,2,3,4,5,6,7,8,9,10,11}...), s的指向的还是原来自己的数组,但是,t指向的是新的数组。这个原因是因为底层数组不够用,重新分配一个新的数组装填这些内容之后返回slice给t ,而s的底层数组的长度和内容均没有变化。这样理解对么?@Cynhard

Cynhard
Cynhard · #4 · 8年之前
javasgljavasgl #3 回复

#2楼 @Cynhard 当执行append的内容超出底层数组长度时,`t=append(s,[]int{1,2,3,4,5,6,7,8,9,10,11}...)`, s的指向的还是原来自己的数组,但是,t指向的是新的数组。这个原因是因为底层数组不够用,重新分配一个新的数组装填这些内容之后返回slice给t ,而s的底层数组的长度和内容均没有变化。这样理解对么?@Cynhard

是的

ddxx11223
ddxx11223 · #5 · 8年之前
javasgljavasgl #3 回复

#2楼 @Cynhard 当执行append的内容超出底层数组长度时,`t=append(s,[]int{1,2,3,4,5,6,7,8,9,10,11}...)`, s的指向的还是原来自己的数组,但是,t指向的是新的数组。这个原因是因为底层数组不够用,重新分配一个新的数组装填这些内容之后返回slice给t ,而s的底层数组的长度和内容均没有变化。这样理解对么?@Cynhard

那如果是s=append(s,[]int{1,2,3,4,5,6,7,8,9,10,11}...)的话呢

ddxx11223
ddxx11223 · #6 · 8年之前
CynhardCynhard #2 回复

切片是基于数组的。可以把切片简单的理解为数组中的一段,它保留了指向数组中某个元素(可以不是第一个元素)的指针,以及它本身的长度(也就是切片的大小)。`var s=make([]int,0,10)`这条语句创建了一个长度为10的数组,并在该数组之上建立了一个切片s,该切片保留指向数组第一个元素的指针,以及它的长度(0)。`t = append(s,1,2,3,4)` 这条语句向 s 指向的数组中追加了 4 个元素(注意这里 s 并没有变化,它的长度仍然是0,仅仅是底层数组变了)并返回新的切片(指向数组的第一个元素,长度为4)赋值给 t 。现在 s 和 t 都指向同一个数组的第一个元素,因此他们的地址是相同的。而 s 的长度是0,t 的长度是4. 可以参考go的文档:go doc builtin.make 以及 go doc builtin.append

谢谢回答,这个点现在清楚多了,万分感谢

ddxx11223
ddxx11223 · #7 · 8年之前
CynhardCynhard #2 回复

切片是基于数组的。可以把切片简单的理解为数组中的一段,它保留了指向数组中某个元素(可以不是第一个元素)的指针,以及它本身的长度(也就是切片的大小)。`var s=make([]int,0,10)`这条语句创建了一个长度为10的数组,并在该数组之上建立了一个切片s,该切片保留指向数组第一个元素的指针,以及它的长度(0)。`t = append(s,1,2,3,4)` 这条语句向 s 指向的数组中追加了 4 个元素(注意这里 s 并没有变化,它的长度仍然是0,仅仅是底层数组变了)并返回新的切片(指向数组的第一个元素,长度为4)赋值给 t 。现在 s 和 t 都指向同一个数组的第一个元素,因此他们的地址是相同的。而 s 的长度是0,t 的长度是4. 可以参考go的文档:go doc builtin.make 以及 go doc builtin.append

如果我s=s[0:10] 这样操作一下,是不是可以改变s的len?把s的len变成了10

javasgl
javasgl · #8 · 8年之前
ddxx11223ddxx11223 #5 回复

#3楼 @javasgl 那如果是`s=append(s,[]int{1,2,3,4,5,6,7,8,9,10,11}...)`的话呢

s=append(s,[]int{1,2.......N}...) 这样的,就和 另外一个t完全无关了。这和s 有关,如果没有超过长度,则 s 的指向的地址不变,如果超过长度,则s会指向一个新的地址

Cynhard
Cynhard · #9 · 8年之前
ddxx11223ddxx11223 #7 回复

#2楼 @Cynhard 如果我s=s[0:10] 这样操作一下,是不是可以改变s的len?把s的len变成了10

是的,不过不能越界,比如 s[0:11] 会触发 panic

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传