概念:

  • 切片出现的原因也是因为数组的可操作性不高。切片的长度是不固定的,可以追加数据,可以理解切片是一个动态数组,切片的底层是一个结构体
  • 切片类型(slice)本身并不是动态数组或数组指针。它内部通过指针引用底层数组,设定相关属性将操作限定在指定范围内。当需要时,会申请更大的内存,将当前数据复制过去, 以实现类似动态数组的功能。
type slice struct { array unsafe.Pointer len int cap int
}

切片的创建:

可直接创建切片对象,无需预先准备数组。因为是引用类型,须使用make函数或显式初始化语句,它会自动完成底层数组内存分配

普通格式:

var 切片名 [] 数据类型

自动推导类型创建切片:

切片名 := [] 类型{}

make函数创建切片:
长度是已经初始化的空间,容量是已经开辟的空间,包括已经初始化的空间和空闲的空间

// 长度是不能大于容量的,容量可以省略不写,不写时候就默认和长度的值一样
切片名称 := make ([]切片类型,长度 容量)// 返回切片的容量使用cap,返回切片的长度使用len
fmt.Println(cap(切片名称))

演示:

func main() {s1 := make([]int, 3, 5)    // 指定len、cap,底层数组初始化为零值s2 := make([]int, 3)       // 省略cap,和len相等s3 := []int{10, 20, 5: 30} // 按初始化元素分配底层数组,并设置len、cap,设置索引5的数据为30fmt.Println(s2, len(s2), cap(s2))fmt.Println(s1, len(s1), cap(s1))fmt.Println(s3, len(s3), cap(s3))
}

输出:

[0 0 0] 3 3
[0 0 0] 3 5
[10 20 0 0 0 30] 6 6

切片初始化:

三种创建格式,都是可以通过append向切片添加数据的

初始化格式:

/// 普通格式创建的切片
切片名 [索引] = 值 // 自动推导类型创建的切片
切片名 := [] 类型{数据1,数据2,数据3}// make函数方式创建的切片可以通过append和循环初始化
切片名称 = append(切片名称, 数据1,数据2...)

演示:

func SliceDemo2() {var slice []intslice = append(slice, 1, 2, 3, 4)slice[1] = 111fmt.Println("切片中的数据", slice)fmt.Println("可以通过索引取部分数据", slice[0])fmt.Println("切片长度:", len(slice))
}func SliceDemo03() {slice := []int{1, 2, 3, 4, 5}slice = append(slice, 6, 7, 8, 9, 10)slice[1] = 111fmt.Println("切片中的数据", slice)fmt.Println("可以通过索引取部分数据", slice[0])fmt.Println("切片长度:", len(slice))
}func SliceDemo04() {slice := make([]int, 3, 4)for i := 0; i < len(slice); i++ {slice[i] = i + 1}slice = append(slice, 1)fmt.Println("切片中的数据", slice)fmt.Println("可以通过索引取部分数据", slice[0])fmt.Println("切片长度:", len(slice))fmt.Println("切片容量:", cap(slice))
}

注意下面两种定义方式的区别。前者仅定义了一个[ ]int类型变量,并未执行初始化操作, 而后者则用初始化表达式完成了全部创建过程

func main() {var a []intb := []int{}println(a == nil, b == nil)
}

可获取元素地址,但不能向数组那样直接通过指针(*slice)访问元素内容

func main() {s := []int{0, 1, 2, 3, 4}p := &s     // 取s地址p0 := &s[0] // 取s[0]地址p1 := &s[1]println(p, p0, p1)// 取p中[1]的数据且加100(*p)[1] += 100 // *[]int不支持indexing操作,须先用指针操作符获取[]int对象fmt.Println(s)fmt.Println((*p)[1]) //这里加括号是优先级问题
}

如果元素类型也是切片,那么就能实现类似交错数组的功能

func main() {x := [][]int{{1, 2},{10, 20, 30},{100},}fmt.Println(x[1])x[2] = append(x[2], 200, 300)fmt.Println(x[2])
}

输出:

[1 2]
[10 20 30]
[100]

切片遍历:

遍历和数组一样可以使用普通的for循环和range遍历得到

演示:

func main() {slice := []int{1, 2, 3, 4, 5}for i := 0; i < len(slice); i++ {fmt.Print(slice[i])}for _, v := range slice {fmt.Println(v)}
}

切片截取:

切片截取就是从切片中获取指定的数据
如果初始化切片时,没有指定切片的容量,切片容量是跟随原切片的

切片截取的操作:

操作 含义
s[n] 切片s中索引位置为n的项
s[:] 从切片s的索引位置0到len(s)-1处所获得的切片
s[low:] 从切片s的索引位置low到len(s)-1处所获得的切片
s[:high] 从切片s的索引位置0到high处所获得的切片,len=high
s[low:high] 从切片s的索引位置low到high处所获得的切片,len=high-low
s[low:high:max] 从切片s的索引位置low到high处所获得的切片,len=high-low,cap=max-low
len(s) 切片s的长度,总是<=cap(s)
cap(s) 切片s的容量,总是>=len(s)

func main() {slice := []int{1, 2, 3, 4, 5}/**第一个值:截取的起始索引第二个值:截取的终止索引(不包括该值)第三个值:用来计算切片的容量,可以省略,默认和长度一样容量 = 第三个值 - 第一个值长度 = 第二个值 - 第一个值*/newSlice := slice[0:3:3]fmt.Println("截取后的切片", newSlice)fmt.Println("切片的长度", len(newSlice))fmt.Println("切片的容量", cap(newSlice))// 和复制一样了newSlice2 := slice[:]fmt.Println("截取后的切片", newSlice2)fmt.Println("切片的长度", len(newSlice2))fmt.Println("切片的容量", cap(newSlice2))
}

切片值的修改:

切片截取后返回新切片,对新切片的值进行修改,会影响原来的切片

原因:

切片截取后新的切片,不会给新的切片是指向了原来的切片,没有给新的切片开辟新的空间,所以对于新的切片操作会影响到原来的切片

演示:

func main() {slice := []int{1, 2, 3, 4, 5}newSlice2 := slice[0:3]fmt.Println("切片修改前slice的数据:", slice)newSlice2[0] = 1111fmt.Println("切片修改后slice的数据:", slice)
}

输出:

切片修改前slice的数据: [1 2 3 4 5]
切片修改后slice的数据: [1111 2 3 4 5]

append函数:

append函数是向切片的末尾slice(len)添加数据
如果添加的内容超出了切片初始定义的容量,切片会自动扩容
扩容机制是:上一次的容量 * 2
如果超过1024字节,每次扩容上一次的1/4
append每次扩容都是一个新的内存,和原来的无关联,所以如果是通过参数传递的方式,使用append添加数据,但是不会影响到原切片的数据,原因就是append每次拓展都是一个新的空间,指向的内存不再是原切片。

func main() {slice := make([]int, 3, 4)// 这里定义了切片的长度是3,初始容量是4,系统会对长度赋上默认值,int类型就是0,所以打印3个0fmt.Println("初始切片的数据:", slice, "长度:", len(slice))slice = append(slice, 1)// 添加数据,此时容量是4,数据已经有4个了,如果继续多加点数据,会不会报错fmt.Println("第一次添加数据:", slice, "长度:", len(slice))slice = append(slice, 2, 3, 4, 5, 6, 7, 8, 9)fmt.Println("第二次添加数据:", slice, "长度:", len(slice))
}

输出:

初始切片的数据: [0 0 0] 长度: 3
第一次添加数据: [0 0 0 1] 长度: 4
第二次添加数据: [0 0 0 1 2 3 4 5 6 7 8 9] 长度: 12

copy函数:

把切片2的数据(0索引到len-1)赋值到切片1中
注意:如果切片1的容量不够,则不赋值剩余的数据。如果切片1的数据比切片2的多,从切片2复制的数据是有多少,复制多少。
总结:copy只是复制索引相对应的数据,如果长度不够,不会覆盖原来的数据

格式:

copy(切片1,切片2)

演示:

 // 从切片2复制到切片1,但是切片2的数据比切片1的多,所以,最终只是复制了一部分,也就是索引相对应的数据
func main() {slice := []int{1, 2, 3}slice2 := []int{4, 5, 6, 7, 8, 9}copy(slice, slice2)fmt.Println(slice) // [4 5 6]
}// 从切片1复制到切片1,但是切片1的数据比切片2的少,所以,最终只是复制了一部分,也就是索引相对应的数据
func main() {slice := []int{1, 2, 3}slice2 := []int{4, 5, 6, 7, 8, 9}copy(slice2, slice)fmt.Println(slice2) // [1 2 3 7 8 9]
}

还可直接从字符串中复制数据到[ ]byte

func main() {b := make([]byte, 3)n := copy(b, "abcde")fmt.Println(n, b)
}

切片作为函数参数:

切片可以做为函数的参数,但是在函数中修改切片的值,会影响到原切片
因为切片的底层是结构体,结构体里有个参数Pointer,Pointer会指向切片的内存地址,使用的是浅拷贝方式,所以会影响到原切片值

演示:

func main() {slice := []int{1, 2, 3, 4, 5}SliceDemo10(slice)
}func SliceDemo10(slice []int) {for _, v := range slice {fmt.Println(v)}slice = append(slice, 5, 6, 7)fmt.Println(slice)
}

输出:

1
2
3
4
5
[1 2 3 4 5 5 6 7]

切片求和:

func main() {// 定义变量,并收集用户输入的个数var count intfmt.Println("请输入要求和的个数:")fmt.Scan(&count)// 定义切片,将输入的个数保存到切片slice := make([]int, count)statisticalData(slice)// 求和summation(slice)
}func statisticalData(slice []int) {for i := 0; i < len(slice); i++ {fmt.Printf("请输入第%d个数\n", i+1)fmt.Scan(&slice[i])}
}
func summation(slice []int) {var sum intfor i := 0; i < len(slice); i++ {sum += slice[i]}fmt.Println("和为:", sum)
}

切片求最大值:

func main() {// 定义变量,并收集用户输入的个数var count intfmt.Println("请输入要比较的数:")fmt.Scan(&count)// 定义切片,将输入的个数保存到切片slice := make([]int, count)statisticalData(slice)// 比较最大值maximum(slice)
}func statisticalData(slice []int) {for i := 0; i < len(slice); i++ {fmt.Printf("请输入第%d个数\n", i+1)fmt.Scan(&slice[i])}
}func maximum(slice []int) {max := slice[0]for i := 0; i < len(slice); i++ {if max < slice[i] {max = slice[i]}}fmt.Println("最大值是:", max)
}

Golang——切片使用大全(创建、初始化、遍历、截取、修改、添加、切片的copy、切片作为函数参数、切片求和、切片求最大值)相关推荐

  1. Golang——结构体创建与初始化、结构体与数组、结构体与切片、结构体与map、结构体作为函数参数、结构体方法、结构体方法继承

    结构体: 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合 结构体可以很好的管理一批有联系的数据,使用结构体可以提高程序的易读性,类似于Java的类一样 不能在结构体直接赋值 字段名必须唯一 ...

  2. python append函数二维_python创建与遍历List二维列表的方法

    python创建与遍历List二维列表的方法 python 创建List二维列表 lists = [[] for i in range(3)] # 创建的是多行三列的二维列表 for i in ran ...

  3. 二叉树的创建和遍历-C语言实现

    二叉树的创建和遍历-C语言实现 链式存储结构 struct BinaryTreeNode {//数据char data;//左子树BinaryTreeNode *leftChild;//右子树Bina ...

  4. Golang——map集合初始化、键值操作、map作为函数参数的使用

    map是一种无序的键值对集合,键是不允许重复的,map是通过hash实现的 map最重要的一点是通过key来快速检索数据,key类似于索引,指向数据的值 引用类型不能作为key map的创建: 格式1 ...

  5. Python中字典创建、遍历、添加

    Python中字典创建.遍历.添加 字典是Python中唯一的键-值类型,是Python中非常重要的数据结构,因其用哈希的方式存储数据,其复杂度为O(1),速度非常快.下面列出字典的常用的用途. 一. ...

  6. 二叉链表-创建、遍历(前序、中序、后序、非递归、层次)、复制、计算深度、结点数、销毁(C语言)

    目录 二叉树的定义 二叉树的性质 二叉链表的基本操作 二叉链表的结构定义 前序遍历创建 前序.中序.后序遍历 中序遍历的非递归算法(栈) 层次遍历(队列) 复制二叉树 计算深度 计算总结点数与叶子结点 ...

  7. 关于学习Python的一点学习总结(26->自定义函数及创建初始化数据结构函数)

    62.自定义函数: 1.判断某个对象是否可调用,使用内置函数callable >>> import math>>> x=1>>> y=math.s ...

  8. python创建列表_python创建与遍历List二维列表的方法

    python 创建List二维列表 lists = [[] for i in range(3)] # 创建的是多行三列的二维列表 for i in range(3): lists[0].append( ...

  9. c语言二叉树的生成,C语言实现二叉树的创建以及遍历(递归)

    C语言实现二叉树的创建以及遍历 #include typedef char ElemType; typedef struct BiTNode { ElemType data; struct BiTNo ...

最新文章

  1. linux下/proc/cpuinfo文件
  2. [轉]c#从Excel中读取图片
  3. 评分卡建模—拒绝推断
  4. <马哲>社会基本矛盾2017-12-27
  5. href脱离iframe显示
  6. android意图传递参数返回结果(六)
  7. GraphSAGE 模型解读与tensorflow2.0代码实现
  8. java树洞_SSM框架开发案例——铁大树洞后台管理系统
  9. Ibatis2.0使用说明(二)——配置篇(2)
  10. Mybatis与JDBC批量插入MySQL数据库性能测试及解决方案
  11. bagging和时间序列预测_Simple RNN时间序列预测
  12. 如何用C#写一个简单的Login窗口
  13. 新手必须知道的典型自动脱螺纹注射模设计!!!
  14. 百度itextpdf工具类,快速生成PDF打印模板,itextpdf5加公章
  15. 微信公众号图文 点击显示图片效果
  16. 个人电脑秒变服务器 简单几步,你的电脑也可以成为服务器 (内网穿透)
  17. Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)! To rerun under ARM use: ar
  18. 【Java 基础语法01】 举例描述二进制和十进制的互转
  19. 原生app 嵌入百度h5人脸认证,活体检测方案, HUAWEI mate30 Pro 不兼容处理
  20. RFID智能仓储管理解决方案,你get到了吗-新导智能

热门文章

  1. 提示未检测到 oracle,Oracle RAC [INS-40406] 未检测到现有的 Oracle Grid Infrastructure 软件...
  2. 与40mhz信道不兼容设置_为什么面包板不适合高频电路
  3. java对docker_如何在docker中运行java程序
  4. Java 输出链表的第一个和最后一个元素
  5. Java 将文件的内容复制到另一个文件
  6. mysql联合索引like_MySQL全文索引、联合索引、like查询、json查询速度大比拼
  7. php测试号推送消息失败,信息发送失败是什么原因
  8. 单片机c语言 oxfe,AVR单片机入门及C语言高效设计实践(五)
  9. php环行队列实现,java数组实现队列及环形队列实现过程解析
  10. 【Python】shutil内置模块复制和重命名文件