Gloang中的数组与切片

1. 前言

python和golang中都有切片的用法,但效果却很有不同。

在python中列表属于可变对象, 而python的切片操作会返回一个新的列表,在切片上的操作不会对原有列表数据造成影响。

>>> a = [1,2,3]
>>> b = a
>>> c = a[:]
>>> b[0]=0
>>> a
[0, 2, 3]
>>> b
[0, 2, 3]
>>> c
[1, 2, 3]
>>> c[0]=4
>>> c
[4, 2, 3]
>>> a
[0, 2, 3]
>>> b
[0, 2, 3]

而在golang中恰恰相反, 数组是一个值类型, 当数组作为参数传递时, 实际传递的是一个副本, 而切片可以看做是对底层数组的引用。

2. golang 中的切片

在 Go 语言中,切片(slice)是一种灵活的、可变长的序列类型,它是基于数组(array)类型构建的。

切片是一个由元素组成的序列,每个元素可以是任意的类型。切片有三个重要的属性:

  1. 长度(Length):切片中元素的个数。
  2. 容量(Capacity):切片底层数组的大小,通常是从切片的起始位置到底层数组的末尾位置。
  3. 指针(Pointer):指向底层数组的第一个元素的指针。

切片的声明方式和数组很类似,只不过不需要指定长度,如下所示:

var s []int          // 声明一个切片变量 s,元素类型为 int
var s = []int{1, 2}  // 使用字面量声明一个切片

可以使用内置函数 make() 来创建一个指定类型的切片。make() 函数的第一个参数指定了切片的类型,第二个参数指定了切片的长度,第三个参数(可选)指定了切片的容量。例如:

s := make([]int, 5)        // 长度为 5,容量为 5 的 int 类型切片
s := make([]int, 5, 10)    // 长度为 5,容量为 10 的 int 类型切片

切片可以通过索引来访问其元素,也可以通过内置函数 append() 来动态添加元素。例如:

s := []int{1, 2, 3, 4, 5}  // 创建一个 int 类型的切片
s[0] = 6                  // 修改第一个元素为 6
s = append(s, 6, 7)       // 添加两个元素 6 和 7 到切片 s 的末尾

切片的底层实现是数组,切片与数组的主要区别在于长度和容量。切片的长度可以在运行时动态改变,而数组的长度是固定的。因此,使用切片可以更加灵活地处理数据。

切片还有一个重要的特性是切片表达式(slice expression),可以用于截取切片中的一段序列。例如:

s := []int{1, 2, 3, 4, 5}
s1 := s[1:3]  // 获取切片 s 中下标从 1 到 2 的元素,即 [2, 3]

在 Go 语言中,切片(slice)是一种灵活的、可变长的序列类型,它是基于数组(array)类型构建的。

切片是一个由元素组成的序列,每个元素可以是任意的类型。切片有三个重要的属性:

  1. 长度(Length):切片中元素的个数。
  2. 容量(Capacity):切片底层数组的大小,通常是从切片的起始位置到底层数组的末尾位置。
  3. 指针(Pointer):指向底层数组的第一个元素的指针。

切片的声明方式和数组很类似,只不过不需要指定长度,如下所示:

var s []int          // 声明一个切片变量 s,元素类型为 int
var s = []int{1, 2}  // 使用字面量声明一个切片

可以使用内置函数 make() 来创建一个指定类型的切片。make() 函数的第一个参数指定了切片的类型,第二个参数指定了切片的长度,第三个参数(可选)指定了切片的容量。例如:

s := make([]int, 5)        // 长度为 5,容量为 5 的 int 类型切片
s := make([]int, 5, 10)    // 长度为 5,容量为 10 的 int 类型切片

切片可以通过索引来访问其元素,也可以通过内置函数 append() 来动态添加元素。例如:

s := []int{1, 2, 3, 4, 5}  // 创建一个 int 类型的切片
s[0] = 6                  // 修改第一个元素为 6
s = append(s, 6, 7)       // 添加两个元素 6 和 7 到切片 s 的末尾

切片的底层实现是数组,切片与数组的主要区别在于长度和容量。切片的长度可以在运行时动态改变,而数组的长度是固定的。因此,使用切片可以更加灵活地处理数据。

切片还有一个重要的特性是切片表达式(slice expression),可以用于截取切片中的一段序列。例如:

s := []int{1, 2, 3, 4, 5}
s1 := s[1:3]  // 获取切片 s 中下标从 1 到 2 的元素,即 [2, 3]

切片表达式包含两个参数,第一个参数表示起始位置,第二个参数表示结束位置(不包含该位置的元素)。如果省略第一个参数,则默认为 0;如果省略第二个参数,则默认为切片的长度。

3. golang 中的数组与切片

在 Go 语言中,数组和切片都可以用来存储一组值,但它们在很多方面是不同的。

  • 首先,数组的长度是固定的,一旦定义了长度,就不能再改变。而切片的长度可以动态扩容和缩容,因此可以更灵活地处理数据。

  • 其次,数组是一个值类型,当将一个数组传递给函数时,实际上传递的是该数组的一个副本。因此,如果在函数中修改了数组的元素,原始数组不会受到影响。而切片是一个引用类型,当将一个切片传递给函数时,实际上传递的是该切片底层数组的地址。因此,如果在函数中修改了切片中的元素,原始切片和其他引用该底层数组的切片都会受到影响。

  • 最后,数组的定义方式为 [n]T,其中 n 表示数组的长度,T 表示数组中元素的类型。而切片的定义方式为 []T,其中 T 表示切片中元素的类型。因此,如果将一个数组作为参数传递给函数,实际上传递的是该数组的副本,而不是数组本身。如果要传递数组的地址,需要将数组转换为切片类型,然后将切片传递给函数。例如:

func printS(s []int) {
	fmt.Println(s) // 输出[1 2 3]
	fmt.Println("长度:", len(s), "容量:", cap(s)) // 两个值都是3
}

func main() {
	arr := [3]int{1, 2, 3} // 创建一个 int 类型的切片
	// printS(arr) // 报错
	s := arr[:]
	printS(s)
	s[0] = 0
	fmt.Println("arr[0]", arr[0]) // 输出0
}


4. 切片的拷贝

在有些场景中,我们并不希望切片中的内容被修改,可以借助内置函数 copy() 来拷贝切片。

在 Go 中,可以使用内置函数 copy() 来拷贝切片。

copy() 函数的语法为:

copy(destSlice []T, srcSlice []T) int

其中,destSlice 是目标切片,srcSlice 是源切片,T 是切片的元素类型,函数返回值为拷贝的元素个数。

copy() 函数会将源切片的元素复制到目标切片中,如果源切片的长度小于目标切片的长度,则只会拷贝源切片的部分元素;如果源切片的长度大于目标切片的长度,则只会拷贝目标切片的部分元素。如果目标切片的长度小于源切片的长度,那么目标切片中剩余的元素会保持不变。

以下是一个使用 copy() 函数拷贝切片的例子:

func main() {
	slice1 := []int{1, 2, 3, 4, 5}
	slice2 := make([]int, len(slice1))
	slice3 := make([]int, 3)
	slice4 := make([]int, 10)
	var slice5 []int
	// 将 slice1 的元素拷贝到 slice2 中
	n2 := copy(slice2, slice1)
	n3 := copy(slice3, slice1)
	n4 := copy(slice4, slice1)
	n5 := copy(slice5, slice1)
	slice2[0] = 0
	fmt.Println("slice1:", "长度:", len(slice1), "容量:", cap(slice1), slice1)
	fmt.Println("slice2:", "拷贝长度", n2, "长度:", len(slice2), "容量:", cap(slice2), slice2)
	fmt.Println("slice3:", "拷贝长度", n3, "长度:", len(slice3), "容量:", cap(slice3), slice3)
	fmt.Println("slice4:", "拷贝长度", n4, "长度:", len(slice4), "容量:", cap(slice4), slice4)
	fmt.Println("slice5:", "拷贝长度", n5, "长度:", len(slice5), "容量:", cap(slice5), slice5)
}

运行以上代码会输出:

slice1: 长度: 5 容量: 5 [1 2 3 4 5]
slice2: 拷贝长度 5 长度: 5 容量: 5 [0 2 3 4 5]
slice3: 拷贝长度 3 长度: 3 容量: 3 [1 2 3]
slice4: 拷贝长度 5 长度: 10 容量: 10 [1 2 3 4 5 0 0 0 0 0]
slice5: 拷贝长度 0 长度: 0 容量: 0 []xxxxxxxxxx slice1: 长度: 5 容量: 5 [1 2 3 4 5]slice2: 拷贝长度 5 长度: 5 容量: 5 [0 2 3 4 5]slice3: 拷贝长度 3 长度: 3 容量: 3 [1 2 3]slice4: 拷贝长度 5 长度: 10 容量: 10 [1 2 3 4 5 0 0 0 0 0]slice5: 拷贝长度 0 长度: 0 容量: 0 []slice1: [1 2 3 4 5]slice2: [1 2 3 4 5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值