<>强片介绍强>
数组的长度在定义之后无法再次修改,数组是值类型,每次传递都将产生一份副本。显然这种数据结构无法完全满足开发者的真实需求。在初始定义数组时,我们并不知道需要多大的数组,因此我们就需要“动态数组”。在去里面这种数据结构叫切片,切片并不是真正意义上的动态数组,而是一个引用类型.slice总是指向一个底层数组,切片的声明也可以像数组一样,只是不需要长度,它是可变长的,可以随时往片里面加数据。
初看起来,数组切片就像一个指向数组的指针,实际上它拥有自己的数据结构,而不仅仅是个指针。数组切片的数据结构可以抽象为以下3个变量:
1。一个指向原生数组的指针(点):指向数组中片指定的开始位置;
2.数组切片中的元素个数(len):即片的长度;
3.数组切片已分配的存储空间(cap):也就是片开始位置到数组的最后位置的长度。
从底层实现的角度来看,数组切片实际上仍然使用数组来管理元素,基于数组,数组切片添加了一系列管理功能,可以随时动态扩充存放空间,并且可以被随意传递而不会导致所管理的元素被重复复制。
<>强片声明强>
声明片时方括号[]内没有任何数据
声明一个元素类型为int的片
var mySlice [] int ,,声明两个元素类型为字节的slice ,,
golang中的部分非常强大,让数组操作非常方便高效。在开发中不定长度表示的数组全部都是片。但是很多同学对切片的模糊认识,造成认为golang中的数组是引用类型,结果就是在实际开发中碰到很多坑,以至于出现一些莫名奇妙的问题,数组中的数据丢失了。
下面我们就开始详细理解下片、理解后会对开发出高效的程序非常有帮助。
这个是切片的数据结构,它很简单,一个指向真实数组地址的指针ptr,片的长度len和容量上限。
其中兰和帽就是我们在调用len(片)和帽(片)返回的值。
我们来按照片的数据结构定义来解析出ptr, len,帽
//按照上图定义的数据结构 类型片结构{ ptr不安全。//数组指针的指针 len int//片长度 帽int//片的能力 }
下面写一个完整的程序,尝试把golang中片的内存区域转换成我们定义的切进行解析
主要包 导入( “fmt” “不安全” )//按照上图定义的数据结构 类型片结构{ ptr不安全。//数组指针的指针 len int//片长度 帽int//片的能力 }//因为需要指针计算,所以需要获取int的长度//32位整数长度=4//64位整数长度=8 var intLen=int (unsafe.Sizeof (int (0))) 函数main () { s:=(int []、10、20)//利用指针读取片记忆的数据 如果intLen==4{//32位 m:=*(* 4 + 4 * 2字节)(unsafe.Pointer (,)) fmt。Println(“片记忆:“米) 其他}{//64位 m:=*(*(8 + 8 * 2)字节)(unsafe.Pointer (,)) fmt。Println(“片记忆:“米) }//把片转换成自定义的片结构 片:=(*片)(unsafe.Pointer (,)) fmt。Println(“片结构:“片) fmt。Printf (" ptr: % v len: % v帽:% v \ n”, slice.ptr,切片。len slice.cap) fmt。Printf (" golang片len: % v帽:% v \ n”, len (s),帽(s)) s [0]=0 [1]=1 [2]=2//转成数组输出 加勒比海盗:=* (* [3]int) (unsafe.Pointer (slice.ptr)) fmt。Println(“数组值:“arr)//修改片的莱恩 片。len=15 fmt。Println(“切兰:“slice.len) fmt。Println (“golang片兰:“,len (s)) } >之前运行一下查看结果
美元去运行slice.go 片记忆:[0 64 6 32 200 0 0 0 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0] 片结构:,{0 xc820064000 10 20} ptr: 0 xc820064000 len: 10帽:20 golang片len: 10帽:20 数组的值(0 1 2): 片len: 15 golang片len: 15 >之前看到了,golang片的记忆内容,和自定义的切片的值,还有按照切片中的指针指向的内存,就是实际数组数据。当修改了切片中的len, len (s)也变了。
接下来结合几个例子,了解下片一些用法
浅谈golang切片切片原理