您的位置 首页 golang

从一道面试题看golang slice


之前遇到一道感觉很不错的slice面试题,这里分享出来,先不贴答案了大家可以先思考下每个地方的打印会是什么;最后再给大家公布答案
    v := make([]int, 0, 5)    v = append(v, 2, 3, 5)    a := append(v, 0, -1)    fmt.Println(v)     fmt.Println(a)     b := append(v, 1)    fmt.Println()    fmt.Println(v)     fmt.Println(a)     fmt.Println(b)     c := append(v, 6, 7, 8, 9)    fmt.Println()    fmt.Println(v)     fmt.Println(a)     fmt.Println(b)     fmt.Println(c)     d := append(v, 12)    fmt.Println(d)     fmt.Println(v)     fmt.Println(a)     fmt.Println(b)     fmt.Println(c)     fmt.Println(d) 
在解这道面试题之前先来看下slice常用用法

一般通过make([]T,len,cap)来创建slice
其中cap可以省略则跟len的值相同
len 表示存储的元素个数,cap表示容量

slice 初始化姿势
    // 1、初始化时添加好了数据,这时候len=cap=初始化的数据个数    s1 := []int{1, 2, 3, 4, 5, 6}    fmt.Println(s1, len(s1), cap(s1)) // [1 2 3 4 5 6] 6 6    // 2、只申明 len,cap跟len相同    s2 := make([]int, 5)    fmt.Println(s2, len(s2), cap(s2)) // [0 0 0 0 0] 5 5    // 3、同时申明len,cap    s3 := make([]int, 5, 5)    fmt.Println(s3, len(s3), cap(s3)) // [0 0 0 0 0] 5 5    // 4、先声明一个数组,从数组处申明slice    arr := [5]int{1, 2, 3, 4, 5}    s4 := arr[:]    fmt.Println(arr)                  // [1 2 3 4 5]    fmt.Println(s4, len(s4), cap(s4)) // [1 2 3 4 5] 5 5
slice 的len很容易理解,就是slice元素个数;那cap有什么用呢?下面通过例子来看下
    s1 := make([]int, 5, 6)    fmt.Println(s1, len(s1), cap(s1))    fmt.Printf("%p\n", s1)    s1 = append(s1, 1)    fmt.Println(s1, len(s1), cap(s1))    fmt.Printf("%p\n", s1)    s1 = append(s1, 2)    fmt.Println(s1, len(s1), cap(s1))    fmt.Printf("%p\n", s1)    s1 = append(s1, 3)    fmt.Println(s1, len(s1), cap(s1))    fmt.Printf("%p\n", s1)=====================================================[0 0 0 0 0] 5 60xc000216000[0 0 0 0 0 1] 6 60xc000216000[0 0 0 0 0 1 2] 7 120xc000030660[0 0 0 0 0 1 2 3] 8 120xc000030660
从上面的结果可以看出来,slice cap是包含len的,也就是说len是cap的一部分,而cap-len的部分是待append数据时存放数据的部分,在打印slice时也是不展示的;slice在append数据时如果cap-len还有空间则会将数据添加到这部分空间中,如果cap-len已经为0,则slice需要扩充整个slice的cap,扩充的元素个数就是当前slice的cap大小。

就如上面的例子中在append 1时 cap还有剩余空间可以放数据所以添加之后 s1的地址没变;在append 2时 cap已经为0了所以这时候需要对s1做扩容操作;扩容的数据量就是初始化s1时设置的cap大小6,然后将之前的数据重新copy的新的slice中,所以可以看到扩容之后slice的地址也发生了变化;扩容之后的cap大小为12;所以在初始化slice时给个合理的cap是非常重要的;因为slice在扩容时是按照当前cap的大小成倍增长的

slice 的本质

slice在真正做存储时其实是对应着一个数组;而slice只是这个数组的视图而已;slice的len就是slice这个视图能够看到这个底层数组的窗口大小,而cap是这个底层数组的大小

假如初始化一个 s := make([]int,8,13);这时候s跟底层数组如下图所示

slice存储

如上图所示不管用那种方式初始化slice,最终在底层都是通过一个数组来存储数据,而slice只是这个底层数组的一个视图,而len就是这个视图的窗口大小;这个类似于数据库中的View的概念;有了这个基础之后我来再回头看文章开头说的面试题就很好做了

我们先把文章开头的面试题以及答案贴出来,下面再通过图示的方式来解答
    // v底层数组值 2,3,5,0,-1    v := make([]int, 0, 5)    v = append(v, 2, 3, 5)    a := append(v, 0, -1)    fmt.Println(v) // 2,3,5    fmt.Println(a) // 2,3,5,0,-1    // v底层数组值 2,3,5,1,-1    b := append(v, 1)    fmt.Println()    fmt.Println(v) // 2,3,5    fmt.Println(a) // 2,3,5,1,-1    fmt.Println(b) // 2,3,5,1    // v底层数组值 2,3,5,1,-1,6,7,8,9    c := append(v, 6, 7, 8, 9)    fmt.Println()    fmt.Println(v) // 2,3,5    fmt.Println(a) // 2,3,5,1,-1    fmt.Println(b) // 2,3,5,1    fmt.Println(c) // 2,3,5,6,7,8,9    // v底层数组值 2,3,5,12,-1    d := append(v, 12)    fmt.Println()    fmt.Println(d) // 2,3,5,12    fmt.Println(v) // 2,3,5    fmt.Println(a) // 2,3,5,12,-1    fmt.Println(b) // 2,3,5,12    fmt.Println(c) // 2,3,5,1,6,7,8,9    fmt.Println(d) // 2,3,5,12
1、第一层打印
    v := make([]int, 0, 5)    v = append(v, 2, 3, 5)    a := append(v, 0, -1)    fmt.Println(v) // 2,3,5    fmt.Println(a) // 2,3,5,0,-1
图示底层数组变化过程
2、第二层打印
    b := append(v, 1)    fmt.Println()    fmt.Println(v) // 2,3,5    fmt.Println(a) // 2,3,5,1,-1    fmt.Println(b) // 2,3,5,1
示意图
3、第三层打印
// v底层数组值 2,3,5,1,-1,6,7,8,9    c := append(v, 6, 7, 8, 9)    fmt.Println()    fmt.Println(v) // 2,3,5    fmt.Println(a) // 2,3,5,1,-1    fmt.Println(b) // 2,3,5,1    fmt.Println(c) // 2,3,5,6,7,8,9
示意图
4、第四层打印
    d := append(v, 12)    fmt.Println()    fmt.Println(d) // 2,3,5,12    fmt.Println(v) // 2,3,5    fmt.Println(a) // 2,3,5,12,-1    fmt.Println(b) // 2,3,5,12    fmt.Println(c) // 2,3,5,1,6,7,8,9    fmt.Println(d) // 2,3,5,12
示意图

文章来源:智云一二三科技

文章标题:从一道面试题看golang slice

文章地址:https://www.zhihuclub.com/1159.shtml

关于作者: 智云科技

热门文章

网站地图