Go语言切片(Slice)

Python里面切片是一种操作,用于取list里面元素。而Go语言的切片则是一种数据类型,而不是一种操作。

Go语言中提供了切片(Slice)作为一种更为灵活、功能强悍的内置类型,它其实是数组的一种抽象。

切片的源码

type slice struct {
	array unsafe.Pointer
	len int
	cap int
}

Slice是原数组在内存中的地址的一个指针,它本身也是一个结构体。Slice建立在数组基础之上,创建一个Slice需要首先创建一个数组。

Go语言的数组同其他语言一样,一经定义,大小就不能改变。这在很多情况下很不方便。因此Go语言内置了切片这种数据类型。切片是数组的一种抽象,但它建立的数组基础之上。与数组相比,切片只保存了原数组的指针、长度、容量等信息,它的长度是不固定的,可以从数组中截取一部分作为切片,也可以动态扩容。

切片声明等价于数组声明不指定数组大小,如下:

var slice_name []type

因此声明数组时一定要指明数组大小,否则会错误的声明成切片。

也可以使用make()函数来声明切片,并初始化:

var slice_name []type = make([]type, length)
// 可以简写为
slice_name := make([]type, length)
// 也可以指定初始容量
silce_name := make([]type, length, capacity)

切片初始化

Go语言的切片,初始化方法除了make()函数可以通过类似于数组的花括号,也支持通过对数组进行类Python那样的切片操作得到,非常灵活,但不支持间隔元素截取。

实例如下:

slice := []int {1, 2, 3, 4, 5}
slice := arr[:]
slice := arr[startIndex:endIndex]

startIndexendIndex都是可选的,下同。

也可以通过切片来初始化切片:

s = slice[startIndex:endIndex]

len()和cap()

len()函数可以获取数组的长度切片的当前长度

cap()函数则可以获取切片的当前能达到的最大长度,即容量

实例如下:

package main

import "fmt"

func main() {
	slice := make([]int, 3, 5)

	fmt.Printf("slice = %d slice lengtn=%d slice capacity=%d", slice, len(slice), cap(slice))
}

// slice = [0 0 0] slice lengtn=3 slice capacity=5

该例可以看出slice默认元素值为0。

注:切片在未经初始化前默认为nil,长度为0。

切片截取

Go语言中的切片支持类Python的元素截取操作,但不支持间隔截取。

语法如下

slice := arr[low:high:max]
package main

import "fmt"

func main() {
	arr := []int {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	fmt.Println(arr[2:8])
}
// [3 4 5 6 7 8]

起始索引和结束索引同样可选。

append()和copy

append()函数用于向已满的切片增加新的元素,可以一次一个或多个元素。

copy函数则用于复制元素。

实例如下:

package main

import "fmt"

func printSliceInfo(s []int) {
	fmt.Printf("current slice=%d length=%d capacity=%d\n", s, len(s), cap(s))
}

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

	slice = append(slice, 4)
	printSliceInfo(slice)

	slice = append(slice, 5, 6, 7, 8, 9, 10)
	printSliceInfo(slice)

	slice_copy := make([]int, len(slice), (cap(slice)*2))
	copy(slice_copy, slice)
	printSliceInfo(slice_copy)
}

// current slice=[1 2 3] length=3 capacity=3
// current slice=[1 2 3 4] length=4 capacity=6
// current slice=[1 2 3 4 5 6 7 8 9 10] length=10 capacity=12
// current slice=[1 2 3 4 5 6 7 8 9 10] length=10 capacity=24

注意capacity如何变化。

append函数仍可向指明了切片max值的slice中添加元素。给定max值会影响容量。实例:

package main

import (
	"fmt"
)

func printSliceInfo(s []int) {
	fmt.Printf("current slice=%d length=%d capacity=%d\n", s, len(s), cap(s))
}

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

	slice = append(slice, 6)
	printSliceInfo(slice)

	slice = append(slice, 7)
	printSliceInfo(slice)

}
// current slice=[2 3] length=2 capacity=3
// current slice=[2 3 6] length=3 capacity=3
// current slice=[2 3 6 7] length=4 capacity=6

func main() {
	arr := [5]int {1, 2, 3, 4, 5}
	slice := arr[1:3:5] // max不能大于数组长度
	printSliceInfo(slice)

	slice = append(slice, 6)
	printSliceInfo(slice)

	slice = append(slice, 7)
	printSliceInfo(slice)

}

// current slice=[2 3] length=2 capacity=4
// current slice=[2 3 6] length=3 capacity=4
// current slice=[2 3 6 7] length=4 capacity=4

比较不同的max值下,capacity的值有何变化。

Slice扩容机制

Slice如何扩容的呢?

  • 如果切片容量小于1024个元素,扩容的时候容量翻倍,即乘以2;如果切片容量超过1024个元素,扩容的时候增加原来容量的四分之一,即增长因子缩小为1.25。
  • 如果扩容之后,还没有触及原数组的容量,那么切片的指针指向的位置,还是原数组;如果扩容之后,超过了原数组的容量,Go就会开辟一块新的内存,把原来的值拷贝过来,不会影响到原数组。

切片做为函数参数

切片也可以做为函数参数,语法类似于数组传递不指明数组大小。

实例:

package main

import (
	"fmt"
)

func sumPartial(s []int) int {
	res := 0
	for i:=0; i< len(s); i++ {
		res += s[i]
	}
	return res
}

func main() {
	arr := [5]int {1, 2, 3, 4, 5}
	slice := arr[1:3]
	fmt.Printf("Sum of element 1 to 3 is: %d", sumPartial(slice))
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值