Go 数组(array) & 切片(slice)
数组
数组是一组固定长度的序列
数组类型
数组的类型不仅和储存元素的类型有关,还和数组长度有关,不同长度的数组是不同的类型
不同类型的数组不能共用一个函数
func main() {
var a [10]int
var b [5]int
var c [5]int32
fmt.Printf("type a: %T,\ntype b: %T,\ntype c: %T", a, b, c)
}
储存数据
由于数组中储存的是值,所以直接传入函数中无法改变原来的值,需要传入地址才能修改原来的值
传值
示例:
func change(a [5]int){
fmt.Println("in change, before change", a)
a[0] = 100
fmt.Println("in change, after change", a)
}
func toChange() {
a := [5]int{0, 0, 0, 0, 0}
fmt.Println("in main, before change", a)
change(a)
fmt.Println("in main. after change", a)
}
输出结果:
in main, before change [0 0 0 0 0]
in change, before change [0 0 0 0 0]
in change, after change [100 0 0 0 0]
in main. after change [0 0 0 0 0]
main 中数组并没有改变
传引用
示例:
func change(a *[5]int){
fmt.Println("in change, before change", *a)
a[0] = 100
fmt.Println("in change, after change", *a)
}
func main() {
a := [5]int{0, 0, 0, 0, 0}
fmt.Println("in main, before change", a)
change(&a)
fmt.Println("in main. after change", a)
}
输出结果:
in main, before change [0 0 0 0 0]
in change, before change [0 0 0 0 0]
in change, after change [100 0 0 0 0]
in main. after change [100 0 0 0 0]
main 中数组发生改变
数组初始化
在数组未进行初始化时,所有的元素都是默认值
// 标准初始化
var array [5]int = [5]int{1, 2, 3, 4, 5}
// 省略类型,会自动判断数组长度与元素类型
var array = [5]int{1, 2, 3, 4, 5}
// 省略长度,会自动判断初始化元素个数来确定长度
var array = [...]int{1, 2, 3, 4, 5}
// 指定索引初始化
var array = [5]int{0: 3, 4: 3}
切片
切片时数组的一个引用,是引用类型
切片长度可变
切片的结构
切片内部储存的只有指向相应数组对应元素的指针和切片的长度、容量
package main
import "fmt"
func main() {
var array = [5]int{1, 2, 3, 4, 5}
var slice = array[2:]
fmt.Printf("array: %p slice: %p\n", &array[2], slice)
}
输出结果:
array: 0xc00001a160 slice: 0xc00001a160
切片从 array[2] 开始,所以指向的就是 array[2]
切片定义
var slice[]int
切片初始化
切片初始化的时候可以自己创建一个数组进行初始化,也可以用 make 进行初始化,但是 make 实际上也是创建了一个数组
// 通过数组初始化
var slice[]int = array[start: end]
// 通过 make 初始化
var slice = make([]int, len)
var slice = make([]int, len, cap)
append
append 用于在切片后面添加元素
用法
// 切片后添加元素
slice = append(slice, elems)
// 切片后添加切片
// slice... 用来将 slice 展开
slice = append(slice, slice...)
实现
由于切片是基于数组的,但是数组的长度不可变,所以进行 append 操作时,
如果内存空间不足:切片会新开辟一段内存空间由于存储新数组,每次开辟都是原来数组长度的两倍
如果内存空间够用:切片会使用原来数组的内存,修改数组中原来的元素
开辟空间示例:
func main() {
var array = [10]int{}
var slice = array[:]
fmt.Printf("slice %p len: %d\n", slice, len(slice))
slice = append(slice, 2)
fmt.Printf("slice %p len: %d(should change)\n", slice, len(slice))
slice = append(slice, slice[:len(slice) - 2]...)
fmt.Printf("slice %p len: %d(should not change)\n", slice, len(slice))
slice = append(slice, 1)
fmt.Printf("slice %p len: %d(should change)\n", slice, len(slice))
}
输出结果:
slice 0xc00001e050 len: 10
slice 0xc0000140a0 len: 11(should change)
slice 0xc0000140a0 len: 20(should not change)
slice 0xc00008c000 len: 21(should change)
初始数组长度为 10,
append 1 个元素之后,长度为 11,由于超过数组最大长度,所以需要开辟新的内存空间,长度为 20,切片指向的地址发生改变
append 9 个元素之后,长度为 20,由于没有超过数组最大长度,所以指向不变
append 1 个元素之后,长度为 21,由于超过数组最大长度,所以需要开辟新的内存空间,长度为 40,切片指向的地址发生改变
修改数组示例:
func main() {
var array = [10]int{8: 1}
var slice = array[: 8]
fmt.Printf("slice %p len: %d\n", slice, len(slice))
fmt.Printf("array: %v\n", array)
slice = append(slice, 2)
fmt.Printf("slice %p len: %d(should not change)\n", slice, len(slice))
fmt.Printf("array: %v\n", array)
slice = append(slice, 2)
fmt.Printf("slice %p len: %d(should not change)\n", slice, len(slice))
fmt.Printf("array: %v\n", array)
slice = append(slice, 2)
fmt.Printf("slice %p len: %d(should change)\n", slice, len(slice))
fmt.Printf("array: %v\n", array)
}
输出结果:
slice 0xc00001e050 len: 8
array: [0 0 0 0 0 0 0 0 1 0]
slice 0xc00001e050 len: 9(should not change)
array: [0 0 0 0 0 0 0 0 2 0]
slice 0xc00001e050 len: 10(should not change)
array: [0 0 0 0 0 0 0 0 2 2]
slice 0xc0000140a0 len: 11(should change)
array: [0 0 0 0 0 0 0 0 2 2]
初始数组长度为 10,但是切片切了前 8 个元素
当 append 的元素未超过数组本身的长度时,会直接修改数组中原来的元素,如果超过了,则开辟新的内存
copy
copy 用来复制切片
如果被复制的切片元素不足,多余部分不变
如果被复制的切片元素超出目标切片长度(与容量无关),则忽略超出部分
用法:
// 切片 dst 变为 切片 scr 的复制
copy(dst []Type, src []Type)
示例:
func main(){
a := []int{1, 2, 3, 4, 5}
b := make([]int, 3, 4)
fmt.Printf("b: %v, a: %v\n", b, a)
copy(b, a)
fmt.Printf("b: %v, cap: %d, prt: %p\n", b, cap(b), b)
b = append(b, 1)
fmt.Printf("b: %v, cap: %d, prt: %p\n", b, cap(b), b)
copy(b, a)
fmt.Printf("b: %v, a: %v\n", b, a)
}
输出结果:
b: [0 0 0], a: [1 2 3 4 5]
b: [1 2 3], cap: 4, prt: 0xc000018140
b: [1 2 3 1], cap: 4, prt: 0xc000018140
b: [1 2 3 4], a: [1 2 3 4 5]
string
字符串 (string) 就是 bytes 组成的不可变的集合
关于字符串类型 <- 点击查看
Go 数组(array) & 切片(slice)的更多相关文章
- 转对象(含length属性)成数组Array.prototype.slice.call(arguments)
我们知道,Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组,除了IE下的节点集合(因为ie下的dom对象是以com对象的形式实现的,js ...
- 类数组转数组Array.prototype.slice.call(arrayLike)
转换方式:Array.prototype.slice.call(arrayLike) 附:(http://www.jianshu.com/p/f8466e83cef0) 首先Array.prototy ...
- JS的数组进行切片slice
代码 var arr = new Array(6) arr[0] = "George" arr[1] = "John" arr[2] = "Thoma ...
- Go通关04:正确使用 array、slice 和 map!
Array(数组) 数组存放的是固定长度.相同类型的数据. 数组声明 var <数组名> = [<长度>]<元素>{元素1,元素2} var arr = [2]in ...
- (66)Wangdao.com第十一天_JavaScript 数组Array
数组 Array 本质上,数组属于一种特殊的对象.typeof 运算符会返回数组的类型是 object 数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2...) // Object.ke ...
- Golang 数组、切片、映射
定义数组 var arr1 [5]int //整型类型 fmt.Println(arr1) //[0 0 0 0 0] //赋值 arr1 = [5]int{1, 2, 3, 4, 5} fmt.Pr ...
- JavaScript中的Array.prototype.slice.call()方法学习
JavaScript中的Array.prototype.slice.call(arguments)能将有length属性的对象转换为数组(特别注意: 这个对象一定要有length属性). 但有一个例外 ...
- go 数组(array)、切片(slice)、map、结构体(struct)
一 数组(array) go语言中的数组是固定长度的.使用前必须指定数组长度. go语言中数组是值类型.如果将数组赋值给另一个数组或者方法中参数使用都是复制一份,方法中使用可以使用指针传递地址. 声明 ...
- Go - 数组 和 切片(array、slice)
一.数组 与其他大多数语言类似,Go语言的数组也是一个元素类型相同的定长的序列. (1)数组的创建 数组有 3 种创建方式: 1) [length]Type 2) [length]Type{value ...
随机推荐
- 让外部的开发机直接访问Kubernetes群集内的服务!
让外部的开发机直接访问Kubernetes群集内的服务! 1.场景 容器化+K8s编排已经是现在进行时把网站的多个项目设计为云原生(Cloud Native)或老项改造为云原生可以获得诸多能力例如无云 ...
- 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解
写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 正 ...
- python爬虫获取天猫与京东的商品价格
git地址: https://gitee.com/zhxs_code/spider_python 目前已简单实现可以爬取指定页面的价格(天猫和狗东的都可以),但是由于天猫与狗东对价格的展示方式和策 ...
- React一键复制
如题,我们怎么在React或者其他的框架中实现一键复制呢,实际上实现一键复制的代码与框架无关,因为他是用的是原生的API,下面我们用React来实现一下 效果: 核心代码: 直接将红框处改为需要 ...
- VS2019 开发Django(九)------内置模板和过滤器
导航:VS2019开发Django系列 紧接上篇,继续介绍Django中的模板,考虑可能篇幅过长,所以分为两部分来讲,今天的主要内容: 1)内置模板和过滤器 母版,继承关系.头部导航和页脚,是需要与其 ...
- [ASP.NET Core 3框架揭秘] 依赖注入[8]:服务实例的生命周期
生命周期决定了IServiceProvider对象采用怎样的方式提供和释放服务实例.虽然不同版本的依赖注入框架针对服务实例的生命周期管理采用了不同的实现,但总的来说原理还是类似的.在我们提供的依赖注入 ...
- PDF提取表格的网页工具——Excalibur
在之前的文章另类爬虫:从PDF文件中爬取表格数据中,我们知道如何利用Python的camelot模块,通过写Python程序来提取PDF中的表格数据.本文我们将学习如何用更便捷的工具从PDF中提取 ...
- Nginx配置实例-反向代理实现浏览器请求Nginx跳转到服务器某页面
场景 Ubuntu Server 16.04 LTS上怎样安装下载安装Nginx并启动: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/detai ...
- 18.JAVA-pull解析XML
1.pull解析介绍 pull解析其实和我们上章学的sax解析原理非常类似,在Android中非常常用. 在java中,需自己获取xmlpull所依赖的类库分别为:kxml2-2.3.0.jar,xm ...
- Android4.4 RIL短信接收流程分析
最近有客户反馈Android接收不到短信,于是一头扎进RIL里面找原因.最后发现不是RIL的问题,而是BC72上报短信的格式不对,AT+CNMA=1无作用等几个小问题导致的.尽管问题不在RIL,但总算 ...