zoukankan      html  css  js  c++  java
  • go语言slice的理解

    Golang slice

     yongsean  作者

    2017.02.17 00:07  打开App

    创建切片,len、cap、append

    b := make([]int, 5)

    println(len(b), cap(b)) // 输出结果是:5, 5

    fmt.Println(b) // 输出结果是:[0 0 0 0 0]

    上述代码是生成默认占用5个0值的切片,下面的输出结果是另一回事

    b := make([]int, 0, 5)

    println(len(b), cap(b)) // 输出结果是:0, 5

    fmt.Println(b) // 输出结果是:[]

    上述代码是生成cap长度为5,实际使用长度为0的切片,在指定的cap内进行append操作,是不会发生内存拷贝扩容操作。

    b := make([]int, 0, 2)

    fmt.Printf("%d, %d, %p ", len(b), cap(b), b) // 0, 2, 0xc420012190

    b = append(b, 1)

    b = append(b, 2)

    fmt.Printf("%d, %d, %p ", len(b), cap(b), b) // 2, 2, 0xc420012190

    b = append(b, 3)

    fmt.Printf("%d, %d, %p ", len(b), cap(b), b) // 3, 4, 0xc420012198

    最后一行输出显示,内存地址跟前2次输出的不一样,并且cap值也在原来的基础上,翻了一倍,相当于做了如下操作:

    // mock append

    tmp := make([]int, 0, cap(b) * 2) // 是当前的cap值的翻倍

    // 复制操作略过。。。

    b = tmp

    copy

    正常的切片copy操作

    a := make([]int, 5)

    a[0] = 1

    a[1] = 2

    fmt.Println(a) // [1 2 0 0 0]

    b := make([]int, 5)

    b[0] = 11

    b[1] = 22

    b[2] = 33

    b[3] = 44

    b[4] = 55

    fmt.Println(b) // [11 22 33 44 55]

    copy(b, a)

    fmt.Println(b) // [1 2 0 0 0]

    另一个效果

    a := make([]int, 5)

    a[0] = 1

    a[1] = 2

    fmt.Println(a) // [1 2 0 0 0]

    b := make([]int, 0, 5) // len(b)!=cap(b)

    b = append(b, 11)

    b = append(b, 22)

    fmt.Println(b) // [11, 22]

    copy(b, a)

    fmt.Println(b) // [1 2]

    第三行的输出,只是[1 2],不是[1 2 0 0 0],是对b切片里len(b)长度内的元素进行对应下标复制操作,假如len(b)==0,那输出结果是[]。 这是需要小心的地方,老司机会一不留神搞错,不了解的人那就更难说。

    切片的切片

    a := make([]int, 5)

    a[0] = 1

    a[1] = 2

    a[2] = 3

    a[3] = 4

    a[4] = 5

    // 原始数据输出

    fmt.Printf("%v, %p ", a, a) // [1 2 3 4 5], 0xc4200141b0

    aslice1 := a[1:]

    // 第一组输出

    fmt.Printf("%v, %p ", aslice1, aslice1) // [2 3 4 5], 0xc4200141b8

    fmt.Println(len(aslice1), cap(aslice1)) // 4 4

    aslice2 := a[1:3]

    // 第二组输出

    fmt.Printf("%v, %p ", aslice2, aslice2) // [2 3], 0xc4200141b8

    fmt.Println(len(aslice2), cap(aslice2)) // 2 4

    aslice3 := a[:3]

    // 第三组输出

    fmt.Printf("%v, %p ", aslice3, aslice3) // [1 2 3], 0xc4200141b0

    fmt.Println(len(aslice3), cap(aslice3)) // 3 5

    上面几组输出,粗看没什么,细看还是有值得注意的

    每组的len和cap值都不太一样

    切片的内存地址不是完全相同

    len的值好理解,无异议。

    cap的值:

    在 第一组输出 中是4,是新切片首地址到原始切片尾地址的个数。

    在 第二组输出 中也是4,是新切片首地址到原始切片尾地址的个数

    在 第三组输出 中是5,道理如上

    内存地址:

    原始数据输出的地址和第三组输出的地址一样

    第一组输出的地址和第二组输出的地址一样

    这样输出的原因是,指向的切片首地址一样。在64位操作系统,int类型占8个字节,第二组输出的地址比第三组输出的地址多8个数值。若有新的切片是如下定义:

    aslice4 := a[2:]

    fmt.Println("%p ", aslice4) // 0xc4200141c0

    那输出结果是:0xc4200141c0,是 0xc4200141b8+8 的结果

  • 相关阅读:
    Unix / 类 Unix shell 中有哪些很酷很冷门很少用很有用的命令?(转)
    5分钟用Spring4 搭建一个REST WebService(转)
    一本好看的书————《反欺骗的艺术——世界传奇黑客的经历分享》
    国内外从事CV相关的企业
    定积分解法
    c++中&和&&有什么差别
    树莓派相关-树莓派串口配置方法
    Linux下df与du两个命令的差别?
    veridata实验举例(2)验证表BONUS与表SALGRADE两节点同步情况
    Java替代C语言的可能性
  • 原文地址:https://www.cnblogs.com/oxspirt/p/7101026.html
Copyright © 2011-2022 走看看