Golang中的Slice与数组
1.Golang中的数组
数组是一种具有固定长度的基本数据结构,在golang中与C语言一样数组一旦创建了它的长度就不允许改变,数组的空余位置用0填补,不允许数组越界。
数组的一些基本操作:
1.创建数组:
func main() {
var arr1 = [...]int{1,2,3,4} //[...]默认为元素的数量即为数组的长度
fmt.Println(len(arr1)) //4
arr1[4] = 5 //panic 数组越界
fmt.Println(arr1)
var arr2 = [10]int{1,2,3,4}
fmt.Println(arr2) //[1 2 3 4 0 0 0 0 0 0]
}
2.数组是值拷贝传递:
func main() {
var arr = [10]int{4,5,7,11,8,9}
fmt.Println(arr) //[4,5,7,11,8,9,0,0,0,0]
//验证数组是值拷贝传递
AddOne(arr)
fmt.Println(arr) //[4,5,7,11,8,9,0,0,0,0]
}
func AddOne(arr [10]int){
arr[9] = 999999
fmt.Println(arr) //[4,5,7,11,8,9,0,0,0,999999]
}
2.Golang中的切片(slice)
1.首先看看slice的源码结构:
type slice struct {
array unsafe.Pointer
len int
cap int
}
slice是一个特殊的引用类型,但是它自身也是个结构体
属性len表示可用元素数量,读写操作不能超过这个限制,不然就会panic
属性cap表示最大扩张容量,当然这个扩张容量也不是无限的扩张,它是受到了底层数组array的长度限制,超出了底层array的长度就会panic
2.slice的创建:
func main() {
var arr = [...]int{0,1,2,3,4,5,6}
slice1 := arr[1:4:5] //{low:high:max} 最多再扩张一个元素
//max超出 len(arr)
//slice2 := arr[1:4:7] //panic
fmt.Println(slice1) //[1,2,3]
slice3 := slice1[1:3:4] //[2,3] 大于4会panic
fmt.Println(slice3)
}
上面代码中创建了一个长度为7的数组arr,同时创建一个基于数组arr的切片slice1,切片引用了数组的index=1到index=3之间的元素,同时也允许切片最大扩张1个元素大小的空间。如果这个扩张空间大于7那么程序就会panic。最后创建了一个基于slice1延申的一个切片slice2,它引用了切片的index=1到index=3之间的元素,由于slice1最大扩容1个元素,因此slice2也最多扩容一个元素,超过了会panic。

创建基于底层数组的slice,其cap取值在: len<=cap<=len(arr)之间
创建基于一个切片的slice,其cap取值在: len(slice1)<=cap<=cap(slice1)之间
3.slice使用make创建
func main() {
var slice = make([]int,3,5) //len=3,cap=5
fmt.Println(slice) //[0,0,0]
slice2:=slice[:5] //slice实现了对slice的扩容,切片长度变为5
fmt.Println(slice2) //[0,0,0,0,0]
}
4.切片作为参数传递
func main() {
var slice = make([]int,3,5) //len=3,cap=5
fmt.Println(slice) //[0,0,0]
slice2:=slice[:5] //slice实现了对slice的扩容,切片长度变为5
fmt.Println(slice2) //[0,0,0,0,0]
slice[0] = 999 //这里slice和slice的index=0位置都是999 因为他们引用的底层数组的index=0位置都是999
fmt.Println(slice)
fmt.Println(slice2)
AddOne(slice) //[8888,0,0]
fmt.Println(slice) //[8888,0,0]
fmt.Println(slice2) //[8888,0,0,0]
}
func AddOne(s []int){
s[0] = 8888
fmt.Println(s)
}
因为切片是个引用类型,所以它作为参数传递给函数,函数操作的实质是底层数组
3.Golang中的切片追加append()
func main() {
var arr = [...]int{1,2,3,4}
fmt.Println(arr) //[1,2,3,4]
slice := arr[:]
fmt.Println(slice) //[1,2,3,4]
slice = append(slice,[]int{5,6,7}...) //此时slice的引用地址已经发生改变了,它引用的底层数组再也不是arr了,而是一个新的数组newarr[1,2,3,4,5,6,7]
fmt.Println(slice) //[1,2,3,4,5,6,7]
//验证slice引用的地址已经发生改变
slice[0] = 666
fmt.Println(arr) //[1,2,3,4]
fmt.Println(slice) //[666,2,3,4,5,6,7]
}
这里由于slice进行追加的元素超出了原来数组的大小,因此go内部会帮我们创建一个新的底层数组,而slice的引用地址不再是arr了,变成了新创建的数组。
还有一种情况就是当slice进行追加的时候没有超出原来数组的大小的时候,其引用地址没有发生改变。
func main() {
var arr = [6]int{1,2,3,4}
fmt.Println(arr) //[1,2,3,4,0,0]
slice := arr[:4]
fmt.Println(slice) //[1,2,3,4]
slice = append(slice,5)
fmt.Println(arr) //[1,2,3,4,5,0]
fmt.Println(slice) //[1,2,3,4,5]
}
4.总结
(1)go是有数组的,只是平时用切片比较多。数组大小一旦创建就不能改变,数组长度大于元素个数的时候会用0补位,这跟其他语言是相通的。
(2)切片slice可以看作是对数组的一切操作,它是一个引用数据类型,其数据结构包括底层数组的地址,以及元素可操作长度len或可扩容长度cap。
(3)要想突破slice的扩容cap限制进行无限扩容就需要使用append()函数进行操作。如果append追加的元素后slice的总长度不超过底层数组的总长度,那么slice引用的地址不会发生改变,反之引用地址会 变成新的数组的地址。
(4)slice是一个抽象的概念,它存在的意义在于方便对一个顺序结构进行一些方便操作,例如查找,排序,追加等等,这个类似于python的list。
Golang中的Slice与数组的更多相关文章
- golang中,slice的几个易混淆点
slice在golang中是最常用的类型,一般可以把它作为数组使用,但是比数组要高效呀.不过,我感觉这个东西用的不好坑太多了.还是需要了解下他底层的实现 slice的结构定义 type slice s ...
- golang中的slice翻转存在以及map中的key判断
//slice翻转 func stringReverse(src []string){ if src == nil { panic(fmt.Errorf("the src can't be ...
- golang中不定参数与数组切片的区别
package main import "fmt" func main() { myfunc1(, , , ) //传递不定数量的参数 myfunc2([], , , }) //传 ...
- 说说不知道的Golang中参数传递
本文由云+社区发表 导言 几乎每一个C++开发人员,都被面试过有关于函数参数是值传递还是引用传递的问题,其实不止于C++,任何一个语言中,我们都需要关心函数在参数传递时的行为.在golang中存在着m ...
- golang中Array与Slice
在golang中有数组和Slice两种数据结构,Slice是基于数组的实现,是长度动态不固定的数据结构,本质上是一个对数组字序列的引用,提供了对数组的轻量级访问.那么在go的函数中以数组或Slice为 ...
- golang中判断两个slice是否相等
在golang中我们可以轻松地通过==来判断两个数组(array)是否相等,但遗憾的是slice并没有相关的运算符,当需要判断两个slice是否相等时我们只能另寻捷径了. slice相等的定义 我们选 ...
- [Golang]-1 Slice与数组的区别
目录 数组 1.创建数组: 2.数组是值拷贝传递: 切片(slice) 1.首先看看slice的源码结构: 2.slice的创建: 3.slice使用make创建 4.切片作为参数传递 5.Golan ...
- golang中数组指针与指针数组的区别实现
指针数组和数组的指针,指的是两个不同的东西. 指针数组是有指针组成的数组,数组的指针是一个数组的指针. package main import "fmt" const MAX ...
- Golang 入门 : 切片(slice)
切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合.切片是围绕动态数组的概念构建的,可以按需自动增长和缩小.切片的动态增长是通过内置函数 append( ...
随机推荐
- 人生中的第一篇OI博客及博客规划
这是笔者第一次在博客园里发表文章,也同样是第一次来写关于OI的一些想法,此篇的主题是想总体对日后的博客有具体的规划. 首先,笔者创办博客并发表观点于看法的目的是记录自己对于题目或竞赛的观念,主要以题解 ...
- php代码没解析成功
在Apache中加载PHP模块 1.打开Apache的配置文件httpd.conf(位于Apache2\conf 目录下). 2.查找 “#LoadModule ssl_module modules/ ...
- [洛谷P4585] [FJOI2015] 火星商店问题
Description 火星上的一条商业街里按照商店的编号 \(1\),\(2\) ,-,\(n\) ,依次排列着 \(n\) 个商店.商店里出售的琳琅满目的商品中,每种商品都用一个非负整数 \(va ...
- 1114 记录一点点吧 RP Axure
- python中[-1]、[:-1]、[::-1]、[n::-1]使用方法
import numpy as np a=np.random.rand(5) print(a) [ 0.64061262 0.8451399 0.965673 0.89256687 0.4851874 ...
- 工具之cut
转自http://www.cnblogs.com/dong008259/archive/2011/12/09/2282679.html cut:正如其名就是“剪”,和sed一样,一行为单位,对数据进行 ...
- http--->http缓存机制系统梳理
http缓存 HTTP请求的过程 从在浏览器地址栏敲入域名-DNS解析-实际IP-(中间可能多个代理服务器分发)- 源服务器,请求抵达源服务器后,在服务器上找到请求的资源,再通过代理服务器一层层的返回 ...
- 【Java并发基础】利用面向对象的思想写好并发程序
前言 下面简单总结学习Java并发的笔记,关于如何利用面向对象思想写好并发程序的建议.面向对象的思想和并发编程属于两个领域,但是在Java中这两个领域却可以融合到一起.在Java语言中,面向对象编程的 ...
- 并发队列之DelayQueue
已经说了四个并发队列了,DelayQueue这是最后一个,这是一个无界阻塞延迟队列,底层基于前面说过的PriorityBlockingQueue实现的 ,队列中每个元素都有过期时间,当从队列获取元素时 ...
- Linux用户在第一次登录时强制更改初始密码
迫使用户更改密码 如果你想迫使用户更改其密码,请使用下面这个命令. $ sudo chage -d0 <user-name> 最初,“-d <N>”选项应该被设成密码的“有 ...