golang 的slice 问题

关于go的slice 底层,这里不多做介绍,就是一个struct和一个数组构成。
通过以下几个例子说明,go对slice的处理方式。

(1)

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)
    t = append(s, 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)
}

运行结果如下:
这里写图片描述
在上例子中:
首先,定义了两个slice,分别为t,s。
这两个slice对应着两个底层数组,注意:%p打印t其实打印的是t对应的底层数组的首元素的地址。

t = append(s, 1, 2, 3, 4) 函数,在s结构对应的数组上添加了1,2,3,4元素,此时的数组没有超过10个元素的限制不需要重新分配空间,append函数生成一个新的slice结构,返回给t,注意此时的s结构里的元素(len,cap,底层数组)并未改变。
所以,此时%p打印的t和s ,都对应于同一个底层数组,也就是s对应的底层数组。
而由于s结构并没有更新,索引打印len(s)和s,结果仍为0,null。而t是最新的slice结构,他会将其对应的底层数组的信息,打印出来。。len(t)=4,t=[1,2,3,4]

(2)

func main() {

    var t = make([]int, 0, 10)
    t = append(t, 1, 2, 3, 4)
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n", t, len(t), t)

    t1 := t
    t2 := t
    t1 = append(t1, 5)
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n", t1, len(t1), t1)
    t2 = append(t2, 6)
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n", t1, len(t1), t1)
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n", t2, len(t2), t2)

}

运行结果如下:
这里写图片描述

在上例中:
定义了一个cap为10个元素的slice t,并且给t对应的底层数组添加了4个元素。
首先,基于t复制了t1,t2两个slice结构,它对应的底层数组同t一摸一样。

t1 = append(t1, 5),
由于t1对应的底层数组并没有超过十个元素,所以它仍指向原来的底层数组,并且更新此时的t1结构的信息(len,cap,底层数组)。所以我们此时打印%p的信息不变,len(t1)和t1发生变化。但是由于此时的t结构仍是之前的结构,没有对其进行更改,所以此时打印的len(t)和t信息,没有发生更改。

t2 = append(t2, 6)
注意此时的t2仍然同t相同,虽然t,t1,t2 都对应与同一个底层数组,但是它们引用的这个底层数组的元素个数并不相同,此时的t2仍然只保存了[1,2,3,4]这四个元素,此时 append(t2, 6) 会在4的后边添加6这个元素,并且更新数组,注意:本来的底层数组已经被t1更改过了,但是t2只包含了四个元素,他并不能拿到第五个元素,所以他会在原数组之上将第五个元素更改为6。而由于t1之前就已经能识别第五个元素了,此时打印t1,会将底层元素的五个元素打印出来,只不过,第五个元素后来被t2更改过了。。

(3)

func main() {
    s := []int{1, 2, 3, 10}
    aa := s
    fmt.Printf("addr:%p \t\tlen:%v cap:%v  content:%v\n", s, len(s), cap(s), s)
    s = append(s, 4)
    fmt.Printf("addr:%p \t\tlen:%v cap:%v  content:%v\n", aa, len(aa), cap(s), aa)
    fmt.Printf("addr:%p \t\tlen:%v cap:%v  content:%v\n", s, len(s), cap(s), s)
}

运行结果如下:
这里写图片描述

在上例子中:
初始化了一个len=4的slice,此时他的底层数组的长度(cap)也为4,
新定义一个aa保存s的信息。

紧接着,在s 的基础之上,添加一个新的元素4,由于此时s对应的底层数组长度不够,需要重新申请一个数组,数组的大小为原数组的一倍。所以此时的aa和s的信息会不同。aa对应的数组和s对应的数组也不是一个了。

(4)

func main() {
    s := []int{1, 2, 3, 10}
    ss := s[1:3]
    for i := range ss {
        ss[i] += 10
    }
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n", s, len(s), s)
    fmt.Printf("addr:%p \t\tlen:%v content:%v\n", ss, len(ss), ss)

    fmt.Println("s= ", s, "     ss=", ss)

    ss = append(ss, 4)
    fmt.Println("s= ", s, "     ss=", ss)
    for i := range ss {
        ss[i] += 10
    }
    fmt.Println("s= ", s, "     ss=", ss)

    ss = append(ss, 5)
    for i := range ss {
        ss[i] += 10
    }
    fmt.Println("s= ", s, "     ss=", ss)
}

运行结果如下:
这里写图片描述

在上例子中:
我们定义了一个cap=4的slice s
ss 为共用s的底层数组的一个slice,只不过他只用了两个元素,所以%p ss和%p s值不同。
ss = append(ss, 4) 将原数组的10更改为4。

for i := range ss {
ss[i] += 10
}

将原数组的每个元素+10

ss = append(ss, 5)导致原数组的长度不够,新申请一个数组,

例子来自网络,记不清哪里的了,自己加以总结得到上述的结果,水平有限,欢迎指出错误。

猜你喜欢

转载自blog.csdn.net/suiban7403/article/details/79599084