今天使用append函数时,遇到了一个小问题,所以深追了一下,和大家分享一下。
努力工作的gopher
首先append是go语言内置的函数,作用就是为切片添加元素,常用操作如下:
s :=[]string{a,b}s=append(s,c)
结果我们打印s就会是:a,b,c 三个元素。但是大家思考一下下面的代码:
s :=[]string{a, b, c}s1 :=append(s, d)fmt.Println(s1:, s1)fmt.Println(ss:, s)
这时我们打印的s1与s分别是多少呢?当然这个也难不倒大家,结果分别是:a b c d 和 a b c。看到这里大家会想,append函数,会将传件来的s从原来的地方拷贝一份,然后再把 d 这个元素放进去,变成 a b c d 再给到 s1。当然目前看来可能是这样的。那么我们再看下面的代码:
s :=[]string{a, b, c}s1 :=append(s[:2], d)fmt.Println(s1:, s1)fmt.Println(ss:, s)
这时打印的结果应该是什么呢?首先我们分析一下,s[:2]这个操作,是截取了s中的前两个元素,也就是 a 和 b。然后再把 d 添加进去,最后s1结果为: a b d。这个是正确的。
那么打印的s是什么呢?按照前一个的逻辑,s应该还是原来的 a b c。但是结果并不是,真正的结果是:a b d。这是为什么呢?
首先s的容量是3,当我们不截取的时候直接append,这是容量是不够的,所以要扩容到了6,扩容一倍。然后将d添加到扩容后的内存,所以这时s1的容量是6。当我们对s截取前两个元素后,那么s的容量仍然是3,但是元素只有前两个,所以在appen的时候,d元素把第三个位置占用了,然后再把新的给了s1,这时,s1容量也是3,值为a b d。同时,由于这个d元素把之前的s的第三个位置占用了,所以s也就成了a b d,也就是最后这个位置元素被覆盖了。
其实道理很简单,如果appen操作中的第一个参数,它的容量能够放下后面添加的元素的数量,那么第一个参数的值就会改变,因为没有扩容,如果它的容量不能够放下后面添加的元素,那么就会扩容,将后面的元素再添加到新扩容的位置,这时第一个元素也就是s并不会改变,只是把扩容后的给了新的s1。
今天说这个是希望大家以后遇到了要知道这是为什么,因为有时我们做append操作上面两种情况都有可能遇到的,尤其是第二种情况,大家一定要知道,这个s也会改变的。