有多种方式可以声明切片,那么不同的声明之间有什么需要注意的呢?

nil切片与长度为0的切片

nil切片:

var data []int

长度为0的切片:

var x = []int{}

它们两个有细微的差别,长度为0的切片在与nil比较时会返回false。在切片与JSON的转换中会用长度为0的切片来表示空切片。

声明切片时赋默认值

data := []int{1, 2, 3, 4}

如果在声明时知道切片所需的大小,但不知道默认值给什么时,最好用make。根据所声明切片的长度和容量,可分为三种情况:

  1. 如果切片被用作缓冲区(buffer),那切片的长度应为非零值。
  2. 如果你明确知道你所需的切片大小,则切片长度和容量可设为一样的。
  3. 其他情况下,用make创建一个长度为0,容量为指定值的切片即可。要添加元素时用append就好。

切片表达式

切片表达式可以在现有的切片的基础上创建子切片。它和python中的有点类似,不过不支持负数索引。语言描述不太直观,用代码演示更容易理解:

a := []int{1, 2, 3, 4}
// 不写起始偏移量则默认从0开始
b := a[:2]
// 不写结束偏移量则默认为切片的长度
c := a[1:]
// 指定起始和结束偏移量,左闭右开
d := a[1:3]
// 都不指定,则起始偏移量为0,结束偏移量为切片长度
e := a[:]
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)
fmt.Println("d:", d)
fmt.Println("e:", e)

输出:

a: [1 2 3 4]
b: [1 2]
c: [2 3 4]
d: [2 3]
e: [1 2 3 4]

共享存储的切片

通过切片表达式得到的子切片是与原切片共享存储的,改变其中的元素会使原切片和子切片中的数据一起变化。

a := []int{1, 2, 3, 4}
b := a[:2]
c := a[1:]
a[1] = 20
b[0] = 10
c[1] = 30
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)

输出:

a: [10 20 30 4]
b: [10 20]
c: [20 30 4]

如果使用append向新切片追加元素的话,同样也会对原切片产生影响:

a := []int{1, 2, 3, 4}
b := a[:2]
c := a[1:]
// 新切片的容量为老切片容量减去新切片起始索引
fmt.Println("cap before:", cap(a), cap(b), cap(c))
// b的长度为2容量为4,与a、c共享同一存储,
// 追加元素后,原来的数据被覆盖
// a[2]=30,c[1]=30
b = append(b, 30)
// c的长度为3,容量为3,追加元素后,发生扩容,
// 与a、b不再共享存储
c = append(c, 50)
// a的长度为4,容量为4,追加元素后,发生扩容,
// 与b不再共享存储
a = append(a, 60)
// 此时再改变a、b切片中元素的值已经不会相互影响了
a[0] = 80
b[1] = 90
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)
fmt.Println("cap after:", cap(a), cap(b), cap(c))

输出:

cap before: 4 4 3
a: [80 2 30 4 60]
b: [1 90 30]
c: [2 30 4 50]
cap after: 8 4 6

因此,为了减少bug,在使用切片表达式创建的子切片时,最好不用append

如果实在需要用append,那最好用全切片表达式来创建子切片。

全切片表达式在原来两个偏移量的基础上增加了一个表示子切片容量偏移量的参数。有点绕,看代码就清楚了:

a := []int{1, 2, 3, 4}
b := a[:2:2]
c := a[2:3:3]
a[1] = 20
fmt.Println("cap before:", cap(a), cap(b), cap(c))
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)
a = append(a, 5)
b = append(b, 6)
c = append(c, 7)
fmt.Println("cap after:", cap(a), cap(b), cap(c))
fmt.Println("a:", a)
fmt.Println("b:", b)
fmt.Println("c:", c)

输出:

cap before: 4 2 1
a: [1 20 3 4]
b: [1 20]
c: [3]
cap after: 8 4 2
a: [1 20 3 4 5]
b: [1 20 6]
c: [3 7]

可以看到,通过第三个参数限制了子切片与原切片共享容量的结束位置,这样在对b使用append时,因为b的容量已经和其长度一致了,append会申请新的内存,避免了对原数据的意外覆盖。


欢迎关注我的微信公众号 江达小记

go学习笔记(10)切片(3)声明时的注意点及切片表达式相关推荐

  1. Hadoop学习笔记—10.Shuffle过程那点事儿

    Hadoop学习笔记-10.Shuffle过程那点事儿 一.回顾Reduce阶段三大步骤 在第四篇博文<初识MapReduce>中,我们认识了MapReduce的八大步骤,其中在Reduc ...

  2. 史上最牛最强的linux学习笔记 10.shell基础

    史上最牛最强的linux学习笔记 10.shell基础 写在最前面: 本文是基于某站的视频学习所得,第一个链接如下: https://www.bilibili.com/video/BV1mW411i7 ...

  3. SpringMVC:学习笔记(10)——整合Ckeditor且实现图片上传

    SpringMVC:学习笔记(10)--整合Ckeditor且实现图片上传 配置CKEDITOR 精简文件 解压之后可以看到ckeditor/lang下面有很多语言的js,如果不需要那么多种语言的,可 ...

  4. springmvc学习笔记(10)-springmvc注解开发之商品改动功能

    springmvc学习笔记(10)-springmvc注解开发之商品改动功能 springmvc学习笔记(10)-springmvc注解开发之商品改动功能 标签: springmvc springmv ...

  5. stm32学习笔记----双串口同时打开时的printf()问题

    stm32学习笔记----双串口同时打开时的printf()问题 最近因为要使用串口2外接PN532芯片实现通信,另一方面,要使用串口1来将一些提示信息输出到上位机,于是重定义了printf(),使其 ...

  6. HALCON 20.11:深度学习笔记(10)---分类

    HALCON 20.11:深度学习笔记(10)---分类 HALCON 20.11.0.0中,实现了深度学习方法. 本章解释了如何在训练和推理阶段使用基于深度学习的分类. 基于深度学习的分类是一种对一 ...

  7. 台大李宏毅Machine Learning 2017Fall学习笔记 (10)Tips for Deep Learning

    台大李宏毅Machine Learning 2017Fall学习笔记 (10)Tips for Deep Learning 注:本博客主要参照 http://blog.csdn.net/xzy_thu ...

  8. Python学习笔记--10.Django框架快速入门之后台管理admin(书籍管理系统)

    Python学习笔记--10.Django框架快速入门之后台管理 一.Django框架介绍 二.创建第一个Django项目 三.应用的创建和使用 四.项目的数据库模型 ORM对象关系映射 sqlite ...

  9. 【论文学习笔记-10】ActiveStereoNet(Google ECCV2018)主动式双目相机自监督学习立体匹配网络

    [论文学习笔记-10]ActiveStereoNet(Google ECCV2018)主动式双目相机自监督学习立体匹配网络) 自监督训练方法 Experiment ORAL 针对双目立体匹配中无监督存 ...

  10. JavaWeb黑马旅游网-学习笔记10【项目代码】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

最新文章

  1. ARIMA+参数选择p+d+q
  2. 【AI】【机器人】AI与机器人的42个终极问题与解答
  3. 如何查看阵列卡的队列深度
  4. 动态时间规整_动态规划-数组系列(10%)
  5. Taro+react开发(8)--控制跳转
  6. 神经网络风格迁移更新篇
  7. Spring框架----Spring框架的基本概念
  8. 为啥连接mysql失败_为什么连接数据库后插入老是失败?
  9. 企业级 SpringBoot 教程 (十四)在springboot中用redis实现消息队列
  10. PAT1008数组元素循环右移问题(2,3测试点不过的解决办法)
  11. layui和js实现二级联动
  12. 帕累托分布(Pareto distributions)、马太效应
  13. 九 Go语言之数据格式
  14. 如何申请Gmail邮箱?_manok_新浪博客
  15. 会唱歌的程序员为何如此受欢迎?
  16. gateway解决过滤器response返回中文乱码
  17. c语言中 输出操作是由库函数,【判断题】在 C语言中,输入操作是由库函数scanf完成,输出操作是由库函数printf完成 。...
  18. WPS文字在线转换成Word
  19. 解决Realtek High Definition Audio麦克风音量过低的简易方法
  20. sql语言学习——数据定义语言

热门文章

  1. vue组件引入外部js同时获取变量,解决重复引入
  2. 什么是国外lead项目
  3. 2021-08-26 网安实验-Linux操作系统加固之配置安全的linux-apache服务器
  4. 过两天就要去面试一家房地产公司了,是销售员,该注意什么呀?_百度知道
  5. 华为云搭建lvs+keepalived+nginx(apache)
  6. linux 双显卡问题。。。
  7. 哔哩哔哩 win8 服务器无响应,win8打开文件夹无响应怎么办?解决教程
  8. C++ Primer Plus书之--C++存储持续性, 作用域和链接性
  9. Java中如何实现结构体?如何对结构体进行排序?
  10. 短视频推广转到直播领域,探店达人做好直播的秘诀是什么