【Go语言基础】slice
一、概述
数组(Array)的长度在定义之后无法再次修改;数组是值类型,每次传递都将产生一份副本。
显然这种数据结构无法完全满足开发者的真实需求。Go语言提供了数组切片(slice)来弥补数组的不足。
切片并不是数组或数组指针,它通过内部指针和相关属性引⽤数组⽚段,以实现变⻓⽅案。
slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度。
二、基本语法
切片的创建和初始化
slice和数组的区别:声明数组时,方括号内写明了数组的长度或使用...自动计算长度,而声明slice时,方括号内没有任何字符。
var s1 []int //声明切片和声明array一样,只是少了长度,此为空(nil)切片
s2 := []int{}
//make([]T, length, capacity) //capacity省略,则和length的值相同
var s3 []int = make([]int, 0)
s4 := make([]int, 0, 0)
s5 := []int{1, 2, 3} //创建切片并初始化
注意:make只能创建slice、map和channel,并且返回一个有初始值(非零)。
// runtime/slice.go
type slice struct {
array unsafe.Pointer // 元素指针
len int // 长度
cap int // 容量
}
【引申1】[3]int 和 [4]int 是同一个类型吗?
不是。因为数组的长度是类型的一部分,这是与 slice 不同的一点。
cap和len的区别
简单点说,len(sli)表示可见元素有几个(即直接打印元素看到的元素个数),而cap(sli)表示所有元素有几个。
比如:
arr := []int{2, 3, 5, 7, 11, 13}
sli := arr[1:4]
fmt.Println(sli) //[3 5 7]
fmt.Println(len(sli))//3
fmt.Println(cap(sli))//5
三、切片的操作
切片截取
操作 | 含义 |
---|---|
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) |
示例说明:
array := []int
操作 | 结果 | len | cap | 说明 |
---|---|---|---|---|
array[:6:8] | [0 1 2 3 4 5] | 6 | 8 | 省略 low |
array[5:] | [5 6 7 8 9] | 5 | 5 | 省略 high、 max |
array[:3] | [0 1 2] | 3 | 10 | 省略 high、 max |
array[:] | [0 1 2 3 4 5 6 7 8 9] | 10 | 10 | 全部省略 |
append
append函数向 slice 尾部添加数据,返回新的 slice 对象:
var s1 []int //创建nil切换
//s1 := make([]int, 0)
s1 = append(s1, 1) //追加1个元素
s1 = append(s1, 2, 3) //追加2个元素
s1 = append(s1, 4, 5, 6) //追加3个元素
fmt.Println(s1) //[1 2 3 4 5 6]
s2 := make([]int, 5)
s2 = append(s2, 6)
fmt.Println(s2) //[0 0 0 0 0 6]
s3 := []int{1, 2, 3}
s3 = append(s3, 4, 5)
fmt.Println(s3)//[1 2 3 4 5]
append函数会智能地底层数组的容量增长,一旦超过原底层数组容量,通常以2倍容量重新分配底层数组,并复制原来的数据:
func main() {
s := make([]int, 0, 1)
c := cap(s)
for i := 0; i < 50; i++ {
s = append(s, i)
if n := cap(s); n > c {
fmt.Printf("cap: %d -> %d\n", c, n)
c = n
}
}
/*
cap: 1 -> 2
cap: 2 -> 4
cap: 4 -> 8
cap: 8 -> 16
cap: 16 -> 32
cap: 32 -> 64
*/
}
copy
函数 copy 在两个 slice 间复制数据,复制⻓度以 len 小的为准,两个 slice 可指向同⼀底层数组。
data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s1 := data[8:] //{8, 9}
s2 := data[:5] //{0, 1, 2, 3, 4}
copy(s2, s1) // dst:s2, src:s1
fmt.Println(s2) //[8 9 2 3 4]
fmt.Println(data) //[8 9 2 3 4 5 6 7 8 9]
注意要目的方需要先分配好空间,不然会丢失。
比如 源有5个,目的3个,则只会拷贝3个过来。
g.textConfigsCopy = make([]string, len(g.textConfigs))
copy(g.textConfigsCopy, g.textConfigs)
切片删除元素
delete_index := 2
//查看删除位置之前的元素和 之后的元素
fmt.Println(slice[:delete_index], slice[delete_index+1:])
//将删除点前后的元素连接起来
slice = append(slice[:delete_index], slice[delete_index+1:]...)
fmt.Println(slice)
四、slice对底层数组的修改
package main
import "fmt"
func main() {
slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s1 := slice[2:5]
fmt.Println(s1) //[2 3 20]
s2 := s1[2:6:7] // 4,5,6,7
s2 = append(s2, 100)
s2 = append(s2, 200)
fmt.Println(s2) //[4 5 6 7 100 200]
s1[2] = 20//0, 1, 2, 3(赋值), 4, 5, 6, 7, 8, 9
fmt.Println(slice) //[0 1 2 3 20 5 6 7 100 9]
//问题1:100怎么来的。
//问题2:为什么100后面是9不是200
}
打印一下看看
package main
import "fmt"
func main() {
slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(len(slice), cap(slice)) //10 10
s1 := slice[2:5]
fmt.Println(s1) //[2 3 20]
fmt.Println(len(s1), cap(s1)) //3 8
s2 := s1[2:6:7] // 4,5,6,7
fmt.Println(len(s2), cap(s2)) // 4 5
s2 = append(s2, 100)
s2 = append(s2, 200)
fmt.Println(s2) //[4 5 6 7 100 200]
//0, 1, 2, 3(赋值), 4, 5, 6, 7, 8, 9
s1[2] = 20
fmt.Println(slice) //[0 1 2 3 20 5 6 7 100 9]
}
100怎么来的:
100后面为什么是9?
s2扩容了。
【Go语言基础】slice的更多相关文章
- 【GoLang】GO语言系列--002.GO语言基础
002.GO语言基础 1 参考资料 1.1 http://www.cnblogs.com/vimsk/archive/2012/11/03/2736179.html 1.2 https://githu ...
- Go语言基础之反射
Go语言基础之反射 本文介绍了Go语言反射的意义和基本使用. 变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息. 值信息:程序运行过程中可动态变化的. 反射介绍 反射是指 ...
- Go语言基础之函数
Go语言基础之函数 函数是组织好的.可重复使用的.用于执行指定任务的代码块.本文介绍了Go语言中函数的相关内容. 函数 Go语言中支持函数.匿名函数和闭包,并且函数在Go语言中属于“一等公民”. 函数 ...
- js-day01-js语言基础
JavaScript简介:JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本 ...
- Golang 入门系列(三)Go语言基础知识汇总
前面已经了 Go 环境的配置和初学Go时,容易遇到的坑,大家可以请查看前面的文章 https://www.cnblogs.com/zhangweizhong/category/1275863.html ...
- Go语言基础之切片
Go语言基础之切片 本文主要介绍Go语言中切片(slice)及它的基本使用. 引子 因为数组的长度是固定的并且数组长度属于类型的一部分,所以数组有很多的局限性. 例如: func arraySum(x ...
- JavaScript 引入方式 语言规范 语言基础 数据类型 常用方法 数组 if_else 比较运算符 for while 函数 函数的全局变量和局部变量 {Javascript学习}
Javascript学习 JavaScript概述 ECMAScript和JavaScript的关系 1996年11月,JavaScript的创造者--Netscape公司,决定将JavaScript ...
- D14——C语言基础学PYTHON
C语言基础学习PYTHON——基础学习D14 20180919内容纲要: 1.html认识 2.常用标签 3.京东html 4.小结 5.练习(简易淘宝html) 1.html初识(HyperText ...
- D04——C语言基础学PYTHON
C语言基础学习PYTHON——基础学习D04 20180810内容纲要: 1 内置函数 2 装饰器 3 生成器 4 迭代器 5 软件目录结构规范 6 小结 1 内置函数 内置函数方法详 ...
- Go 语言基础
Go 语言基础 特点 常用命令 go run 直接运行, 不会生成可执行文件 go build 生成可执行文件, 推荐 加分特点 UTF-8编码 高并发: go 关键字 管道: pipe := mak ...
随机推荐
- C#调用WPS转换文档到PDF的的实现代码。
1.WPS安装,最好用这个版本别的版本不清楚,安装Pro Plus2016版本. https://ep.wps.cn/product/wps-office-download.html 2.添加相关的引 ...
- 关于python导包问题(新手向)
包和模块 首先要弄清这两个概念, 在python 中 一个文件夹中包含__init__.py 文件(这个文件是包的初始化文件,在你导入包或包下面的模块的时候,这个文件会最开始运行),就会被python ...
- Thrift RPC添加access log
前言: 当我们在部署web服务的时候,web容器通常都会记录来自客户端的访问日志.而当我们使用Thrift RPC服务的时候,Thrift服务则不会给我们自动记录客户端的访问日志. 通过这篇文章,你可 ...
- day33-JSON&Ajax01
JSON&Ajax01 JSON 在线文档 AJAX 在线文档 1.JSON介绍 JSON指的是JavaScript对象表示法( JavaScript Object Notation),JSO ...
- pandas中groupby的使用
一.缘由 在爬取大量的数据之后,需要对数据进行分组的处理,于是就使用了groupby,但是我需要的并不是分组之后数据的聚合分析,我需要的是原生的某些数据.但是却找不到网上的相关案例.于是,我就自己尝试 ...
- PHP-表单传值
一.传值引入 了解传值必须要先知道为什么需要传值? 传值的主要作用是为了实现用户数据的定制化,用户与服务端的互交 二.传值的方式 虽然 http协议中有很多数据传输的方式,但在PHP中只有 POST ...
- Django静态文件配置、form表单、request对象、连接数据库、ORM
目录 静态文件配置 静态文件相关配置 1.接口前缀 浏览器停用缓存 2.接口前缀动态匹配 form表单 action 控制数据提交的地址 method 控制数据提交的方法 请求方法补充 get: 朝服 ...
- Python 为什么如此设计?
大概两年半前,我萌生了要创作一个新的系列文章的想法,也就是"Python为什么",试图对 Python 的语法及特性提出"为什么"式的问题,以此加深对它的理解, ...
- python实验报告(第12章)
实验12:GUI界面编程 一.实验目的和要求 1.学会应用常用控件: 2.学会使用BoxSizer布局: 3.学会事件处理. 二.实验环境 软件版本:Python 3.10 64_bit 三.实验过程 ...
- java中json字符串与实体类对象相互转换
1.问题描述 有一个需求是这样的,把实体类转为Json字符串存入redis中,然后再把redis中存放的实体类Json字符串插入数据库中.因此需要涉及到json字符串与实体类对象的相互转换. 2.产生 ...