您现在的位置是:网站首页> 编程资料编程资料
一文详解Golang中的切片数据类型_Golang_
2023-05-26
412人已围观
简介 一文详解Golang中的切片数据类型_Golang_
含义
切片是一个种特殊的数组。是对数组的一个连续片段的引用,所以切片是一个引用类型。切片可以是数组中的一部分,也可以是由起始和终止索引标识的一些项的子集。切片有点像C语言里的指针,指针可以做运算,但代价是内存操作越界,切片在指针的基础上增加了大小,约束了切片对应的内存区域,切片使用中无法对切片内部的地址和大小进行手动调整,因此切片比指针更安全、强大。
定义
切片定义分为三中形式。依次从数组中生成、从切片中生成和全新定义一个切片。
三个要素
1.起始位置:切片引用数组的开始位置。
2.大小:切片中的元素个数。切片中的大小不能超过容量数量。可以使用len()函数对切片统计大小。
3.容量:切片最大可存的元素个数。如果空间不足以容纳足够多的元素,切片就会进行动态“扩容”,此时新切片的长度会发生改变。一般切片的扩容是按照扩容前容量的2倍。可以使用cap()函数对切片容量进行统计。
切片与数组的区别
- 切片是对数组中的连续引用。切片的初始位置指向数组的内存地址,如果切片的值改变,数组对应的值也会对应改变。
- 切片的长度是动态的,本质上是一个可变的动态数组。数组的长度在定义的时候就决定好了,后期是无法修改数组的长度的。
- 切片的长度是可以动态扩容的[如上面容量一次提到的]。
- 切片本身是不保存数据,它只是底层数组的表示。对切片所做的任何修改都将反应到底层数组中。
package main import ( "fmt" ) func main() { numa := [3]int{78, 79, 80} nums1 := numa[:] nums2 := numa[:] fmt.Println("array before change 1", numa) nums1[0] = 100 fmt.Println("array after modification to slice nums1", numa) nums2[1] = 101 fmt.Println("array after modification to slice nums2", numa) }
// output array before change 1 [78 79 80] array after modification to slice nums1 [100 79 80] array after modification to slice nums2 [100 101 80]
当多个切片共享一个底层数组时,每个切片的修改都将反映在底层数组中。
示例代码
// 通过数组定义切片 var array1 = [3]int{1, 1, 3} fmt.Println("数组的元素分别是:", array1) slice1 := array1[0:2] slice1[1] = 11111 fmt.Println("数组的元素分别是:", array1)
输出结果;
数组的元素分别是: [1 1 3]
数组的元素分别是: [1 11111 3]
切片内存分布
切片定义分类
数组生成切片
定义语法:
slice[起始位置:结束位置]
- 1.slice:表示切片的对象。例如从一个数组中生成切片则slice就是定义的数组名称。
- 2.起始位置:从数组中的某个元素的下标开始切,默认中0开始。
- 3.结束位置:切片的结束位置。也就是数组的某个元素下标位置。需要注意的是这里取的是开区间。如果需要取到数组的最后一个元素,结束位置这是数组的长度+1。
- 4.切片的长度:(切片的结束位置-切片的起始位置)。
示例代码
// 通过数组定义切片 array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} slice := array(0:5) // 打印结果为 [A B C D E] // 使用make方式创建切片 slice1 := make([]string, 2, 3) slice1[0] = "1" fmt.Println(slice1) slice2 := make([]string, 2, 3) fmt.Println(slice2) fmt.Println("切片的长度为", len(slice1)) fmt.Println("切片的容量为", cap(slice1)) // output [1 ] [ ] 切片的长度为 2 切片的容量为 3
切片索引
1.切片的起始位置省略,结束位置省略。则默认从数组的开始位置截取到数组的结束位置+1。得到的是和数组内容一样的切片,表示原切片。
// 切片定义省略开始和结束位置 array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} fmt.Println("开始位置和结束位置都缺省",array[:]) // output 开始位置和结束位置都缺省 [A B C D E F G H I G K L]
2.切片的起始位置不省略,结束位置不省略。则根据起始位置和结束位置进行切取。
// 起始位置和结束位置都不省略 array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} slice := array(0:5) // output [A B C D E]
3.起始位置省略,结束位置不省略。则默认从数组的最开始位置切取,直到结束位置为止。
// 起始位置省略,结束位置都不省略 array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} slice := array(:5) // output [A B C D E]
4.起始位置不省略,结束位置省略。则默认从数组的指定起始位置窃取到数组的最后以为(位置为数组长度+1)。
// 起始位置不省略,结束位置省略 array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} fmt.Println("缺省结束位置:",array[2:]) // 打印结果为 缺省结束位置: [C D E F G H I G K L]
5.切片的起始位置和结束位置,不能超出数组的范围。
array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} fmt.Println("切片",array[-1:100]) // 打印结果为 invalid slice index -1 (index must be non-negative)
6.切片的起始位置和结束位置都为0,得到一个空的切片,表示清空切片。一般用于切片的复位。
// 起始位置和结束位置都为0 array := []string{"A","B","C","D","E","F","G","H","I","G","K","L"} fmt.Println("切片",array[0:0]) // 打印结果为 切片: []
直接声明切片
除了可以从原有的数组或者切片中生成切片外,也可以声明一个新的切片,每一种类型都可以拥有其切片类型,表示多个相同类型元素的连续集合,因此切片类型也可以被声明。
定义语法
// 也可以通过一个空的数组形式 var slice []type
1.slice是切片的名称。
2.type是切片的数据类型。
代码示例
// 声明一个整型切片 var slice1 []int // 初始化一个切片 var slice2 []int = []int{}
使用make定义切片
除了上面的几种方式外,如果需要动态地创建一个切片,可以使用 make() 内建函数。
定义语法:
make([]type, size, cap)
- 1.type为切片的数据类型。
- 2.size为切片的大小。
- 3.cap为切片的容量。
切片的大小不能超过容量,容量表示该切片最大的元素个数,切片的大小表示实际的元素个数。例如,一个教室里面可以坐到30个人,现目前坐了10个人。这里的10就表示size,30就表示cap。
代码示例:
// 定义切片 slice1 := make([]string, 2, 3) slice1[0] = "1" fmt.Println(slice1) // 打印如下结果 [1 ]
如果切片在复制的过程中,对应的下标未分配值,则根据数据类型默认分配一个值。例如上面的slince1定义的时2个长度,但是只给下标为0的分配了值,因此下标为1的根据数据类型时string类型,默认分配一个" "值。
常用操作
长度计算
切片长度使用len()计算。
// 计算切片长度 slice1 := make([]string, 2, 3) fmt.Println("切片的长度为", len(slice1)) // 打印结果为 切片的长度为 2
容量计算
切片容量使用cap()计算。
// 计算切片长度 slice1 := make([]string, 2, 3) fmt.Println("切片的长度为", cap(slice1)) // 打印结果为 切片的容量为 3
判断是否为空
在创建变量章节提到, 变量如果创建时未给一个初始化值,编译时会默认分配一个nil的值。因此判断一个切片为空,直接与nil比较。
// 判断空切片 slice3 := make([]string, 2, 3) if slice3 == nil { fmt.Println("slice3是空切片") } else { fmt.Println("slice3不是空切片") } var slice4 []string if slice4 == nil { fmt.Println("slice4是空切片") } else { fmt.Println("slice4不是空切片") }
// output slice3不是空切片 slice4是空切片
// 错误演示 slice1 := make([]int, 2, 5) slice2 := make([]int, 2, 5) if slice1 == slice2 { fmt.Println("相等") } else { fmt.Println("不想等") }
// output slice1 == slice2 (slice can only be compared to nil)
使用make创建切片时,因为定义了一个长度为2,容量为3的切片。虽然切片内容是[ ],但是实际是有值的,只不过是一个空值。切片是动态结构,只能与 nil 判定相等,不能互相判定相等。声明新的切片后,可以使用 append() 函数向切片中添加元素。
切片追加
追加的定义:
使用append()可以动态的给切片的开始位置,结束位置或者中间位置添加元素。
语法格式
append(slice, element)
1.slice,要追加的切片,必须是一个切片。
2.element,向切片中添加的元素,可以是单个元素、多个元素或着切片。
尾部追加
// 切片的开始位置追加元素 var slice []int = []int {1,2,3} // 打印原始切片的长度和容量 fmt.Println("原始切片长度和容量分别是", len(slice), cap(slice)) // 向切片后面追加一个元素 slice = append(slice, 1) fmt.Println(slice) // 向切片后面追加多个元素 slice = append(slice, 6,7,8,9) fmt.Println(slice) // 打印新的切片的长度和容量 fmt.Println("新切片长度和容量分别是", len(slice), cap(slice))
// 打印的内容分别如下 原始切片长度和容量分别是 3 3 [1 2 3 1] [1 2 3 1 6 7 8 9] 新切片长度和容量分别是 8 12
注意事项:
- 1.在切片的尾部添加元素,只能是单个元素或者是多个","隔开的元素,而不能是其他的数据类型。
- 2.如果切片追加元素时,容量不够,切片会自动的扩容。自动扩容的规律是2的倍数。如下代码:
// 验证切片追加元素自动扩容 var numbers []int for i := 0; i < 10; i++ { numbers = append(numbers, i) fmt.P
相关内容
- 总结Golang四种不同的参数配置方式_Golang_
- go语言reflect.Type 和 reflect.Value 应用示例详解_Golang_
- Go中的错误和异常处理最佳实践方法_Golang_
- 利用Go语言实现流量回放工具的示例代码_Golang_
- golang基于errgroup实现并发调用的方法_Golang_
- Go语言制作svg格式树形图的示例代码_Golang_
- 详解Golang如何实现一个环形缓冲器_Golang_
- OpenTelemetry-go的SDK使用方法详解_Golang_
- 搭建Go语言的ORM框架Gorm的具体步骤(从Java到go)_Golang_
- Go语言文件读写操作案例详解_Golang_
点击排行
本栏推荐
