Go之切片

1. 切片的概念

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它的本质是对数组的封装。它支持自动扩容。切片是一个引用类型,它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合。

2. 切片的本质

切片的本质就是对底层数组的分装,其包含了三个信息:底层指向数组的指针,切片的长度(len)和切片的容量(cap)

  • 数组arr := [10]int,切片sli := arr[0:5],示意图如下:
    在这里插入图片描述

  • 切片sli2 := arr[4:7],示意图如下:

在这里插入图片描述

3. 切片的定义

//声明切片的基本语法如下:
var name []T //name表示变量名,T表示切片中元素的类型
package main

import "fmt"

func main(){
	var sli []string				//声明一个字符串切片
	var sli1 =  []int{1, 2, 3}		//声明一个整型切片并初始化
	var sli2 = []bool{false, true}	//声明一个布尔型切片并初始化
	
	//使用make函数构造切片,参数分别为切片的类型,长度,容量
	sli3 := make([]int, 5, 10)	
	
	fmt.Println(sli)	//[]
	fmt.Println(sli1)	//[1 2 3]
	fmt.Println(sli2)	//[false true]

	fmt.Println(len(sli1))	//默认的长度是3
	fmt.Println(cap(sli1))	//默认容量也是3
	
	fmt.Println(len(sli1))	//通过len函数可以获取切片的长度
	fmt.Println(cap(sli1))	//通过cap函数可以获取切片的容量

	fmt.Println(len(sli2))	//2
	fmt.Println(cap(sli2))	//2

	fmt.Println(sli3)		//[0 0 0 0 0]
	fmt.Println(len(sli3))	//5
	fmt.Println(cap(sli3))	//10
}

在这里插入图片描述

切片的底层就是一个数组,所以我们可以基于数组通过切片表达式得到切片。 切片表达式中的low和high表示一个索引范围(左包含,又不包含),也就是下面代码中从数组arr中选出1<=索引值<4的元素组成切片sli,得到的切片长度=high-low,容量等于得到的切片的底层数组的容量。

package main

import "fmt"

func main(){
	arr := [5]int {1, 2, 3, 4, 5}
	var sli []int = arr[1 : 3]

	fmt.Println(len(sli))	//2
	fmt.Println(cap(sli))	//4
	fmt.Println(sli)		//[2 3]
}

简单切片表达式:为了方便起见,可以省略切片表达式中的任何索引。省略了low则默认为0;省略了high,则默认为切片操作数的长度:

package main

import "fmt"

func main(){
	arr := []int{1, 2, 3, 4, 5}
	
	sli := arr[2:]  // 等同于 a[2:len(a)]
	sli := arr[:3]  // 等同于 a[0:3]
	sli := arr[:]   // 等同于 a[0:len(a)]
}

注意事项

  • 对于数组或字符串,若0 <= low <= high <= len(a),则索引合法,否则就会索引越界(out of range)。
  • 对于切片再执行切片表达式时(切片再切片),high的上限边界是切片的容量cap(a),而不是长度。常量索引必须是非负的,并且可以用int类型的值表示;
  • 对于数组或常量字符串,常量索引也必须在有效范围内。如果low和high两个指标都是常数,它们必须满足low <= high。如果索引在运行时超出范围,就会发生运行时panic。
package main

import "fmt"

func main(){
	arr := [...]int{1, 2, 3, 4, 5}
	sli := arr[1:3]	//sli := arr[low, high]

	fmt.Printf("%v %v %v\n", sli, len(sli), cap(sli))

	sli2 := s[3:4]  // 索引的上限是cap(s)而不是len(s)
	fmt.Printf("%v %v %v\n", sli2, len(sli2), cap(sli2))
}

完全切片表达式:对于数组,指向数组的指针,或切片a(注意不能是字符串)支持完整切片表达式:

arr[low : high : max]

上面的代码会构造与简单切片表达式arr[low: high]相同类型、相同长度和元素的切片。切片的容量设置为max-low。在完整切片表达式中只有第一个索引值(low)可以省略;它默认为0。

package main

import "fmt"

func main() {
	arr := [...]int{1, 2, 3, 4, 5}
	sli := arr[1 : 3 : 5]
	
	fmt.Printf("%v %v %v\n", sli, len(sli), cap(sli))
}

4. 切片的遍历

切片的遍历方式和数组是一样的,也支持索引遍历和for range遍历。

package main

import "fmt"

func main(){
	arr := []int{1, 2, 3}

	for i := 0; i < len(arr); i++ {
		fmt.Println(arr[i])
	} 

	for _, value := range arr {
		fmt.Println(value)
	}
}

5. 切片的添加、删除与复制

  • Go语言的内建函数append()可以为切片动态添加元素。 可以一次添加一个元素或者多个元素,也可以添加另一个切片中的元素(后面加…)。
package main

import "fmt"

func main(){
	var sli1 []int
	sli1 = append(sli1, 1, 2, 3) //向切片sli中添加元素
	
	sli2 := []int {4, 5, 6}
	sli1 = append(sli1, sli2...) //向切片sli1中添加其他切片的元素
	
	fmt.Println(sli1)
}

  • Go语言中并没有删除切片元素的专用方法,但可以借助切片本身的特性来删除, 操作方法如下:sli = append(sli[:index], sli[index + 1 :]…)
package main

import "fmt"

func main(){
	//从切片中删除元素
	sli := []int{1, 2, 3, 4, 5, 6, 7}
	fmt.Println(sli)
	//删除索引为5的元素
	sli = append(sli[:5], sli[6:]...)
	fmt.Println(sli)
}

  • Go语言中内建的copy()函数可以将一个切片的数据复制到另外一个切片的空间中,copy()函数的使用格式如下:copy(destSlice, srcSlice)
package main

import "fmt"

func main(){
	srcsli := []int{1, 2, 3, 4, 5}
	destsli := make([]int, 5, 5)
	fmt.Println(srcsli)
	fmt.Println(destsli)

	copy(destsli, srcsli)//将srcsli中的数据复制到destsli中

	fmt.Println(srcsli)
	fmt.Println(destsli)

	destsli[3] = 10
	fmt.Println(destsli)
}

在这里插入图片描述

6. 切片的赋值拷贝

package main

import "fmt"

func main(){
	sli1 := make([]int, 4)//[0 0 0 0]
	sli2 := sli1//俩个切片共享底层数组

	sli2[0] = 100
	fmt.Println(sli2[0])	//100
	fmt.Println(sli1[0])	//100
	
	fmt.Println(sli1)	//[100 0 0 0]
	fmt.Println(sli2)	//[100 0 0 0]
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值