Golang-引用类型
引用类型包括指针(point)、切片(slice)、字典(map)、函数(func)、通道(channel),虽然数据种类很多,但它们都是对程序中一个变量或状态的间接引用。这意味着对任一引用类型数据的修改都会影响所有该引用的拷贝。
1.指针(point)
2.切片(slice)
Golang的Slice源码位于src/runtime/slice.go
src/runtime/slice.go
1.简介
-
Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作[]T,其中T代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。
-
Go 语言切片是对数组的抽象。
-
切片(slice)是对数组一个连续片段的引用(该数组我们称之为相关数组,通常是匿名的),所以切片是一个引用类型(和数组不一样)
-
slice是一个轻量级的数据结构,提供了访问数组子序列(或者全部)元素的功能,而且slice的底层确实引用一个数组对象。
-
slice由三个部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址,slice的第一个元素并不一定就是数组的第一个元素。
-
长度对应slice中元素的数目;长度不能超过容量,
-
容量一般是从slice的开始位置到底层数据的结尾位置。内置的len和cap函数分别返回slice的长度和容量。
长度是slice索引操作的上界 容量是slice分割操作的上界
-
多个slice之间可以共享底层的数据,并且引用的数组部分区间可能重叠。
-
slice不会实际复制一份数据,它只是创建一个新的数据结构,包含了另外的一个指针,一个长度和一个容量数据。 如同分割一个字符串,分割数组也不涉及复制操作:它只是新建了一个结构来放置一个不同的指针,长度和容量。
-
切片提供了计算容量的函数 cap() 可以测量切片最长可以达到多少:它等于切片的长度 + 数组除切片之外的长度。
-
优点
因为切片是引用,所以它们不需要使用额外的内存并且比使用数组更有效率,所以在 Go 代码中切片比
数组更常用。
- 注意
绝对不要用指针指向 slice,切片本身已经是一个引用类型,所以它本身就是一个指针!
声明切片的格式是: var identifier []type(不需要说明长度)。
一个切片在未初始化之前默认为 nil,长度为 0。
2.定义
2.1.方式1
var slice []data_type
释义:
slice:切片名称
data_type:切片的数据类型
注意:
此时切片中的[]是空的,切片的长度和容量均为0
func main() {
var slice []int
fmt.Println(slice)
fmt.Println("len = ",len(slice),",cap = ",cap(slice))
}
2.2.方式2
slice := []data_type{}
释义:
slice:切片名称
data_type:切片的数据类型
注意:
此时切片中的[]是空的,切片的长度和容量均为0
func main() {
slice := []int{}
fmt.Println(slice)
fmt.Println("len = ", len(slice), ",cap = ", cap(slice))
}
2.3.方式3
slice := make([]data_type,len,cap)
释义:
slice:切片名称
data_type:切片的数据类型
len:切片的长度
cap:切片的容量
func main() {
slice := make([]int, 0, 0)
fmt.Println(slice)
fmt.Println("len = ", len(slice), ",cap = ", cap(slice))
}
2.4.方式4
通过数组切割得到切片
var array_name = [size]type{}
slice := array_name[:]
释义:
array_name:数组名称
size:数组长度/大小
slice:切片名称
data_type:切片的数据类型
注意:
此时的切片的元素不是[],长度和容量根据数组的大小来确定,此时的切片长度=容量
func main() {
var array = [10]int{}
slice := array[:]
fmt.Println(slice)
fmt.Println("len = ", len(slice), ",cap = ", cap(slice))
}
3.初始化
3.1.先定义后初始化
var slice = []data_type
slice = append(slice,data1,data2)
或者:
slice := []data_type
slice = append(slice,data1,data2)
释义:
slice:切片名字
data_type:数据类型
append():添加数据的函数
data1,data2:数据
3.2.定义并初始化
var slice = []data_type{data1,data2}
或者:
slice := []data_type{data1,data2}
4.访问
slice[index]
5.遍历
5.1.索引遍历
索引范围为:0 到 len(array)-1
func main() {
var slice = []int{1, 2, 3, 4, 5,}
for index := 0; index < len(slice); index++ {
fmt.Println(slice[index])
}
}
5.2.使用范围range进行遍历
func main() {
var slice = []int{1, 2, 3, 4, 5,}
for index, value := range slice {
fmt.Printf("slice[%d] = %d \n",index,value)
}
}
6.下标越界
6.1.正向越界
引发panic异常
func main() {
var slice = []int{1, 2, 3, 4, 5,}
slice[6] = 0
fmt.Println(slice)
}
func main() {
var slice = []int{1, 2, 3, 4, 5,}
for index := 0; index <= len(slice); index++ {
fmt.Println(slice[index])
}
}
6.2.反向越界
操作时候,编译不通过,提示索引必须为非负,遍历时候,负索引会导致panic异常
func main() {
var slice = []int{1, 2, 3, 4, 5,}
slice[-1] = 100
fmt.Println(slice)
}
func main() {
var slice = []int{1, 2, 3, 4, 5,}
for index := -1; index < len(slice); index++ {
fmt.Println(slice[index])
}
}