Golang 切片追加深入理解(含例子) slice append

切片追加时的长度和容量变化

初始化时支持指定长度和容量,初始值为零值
追加到容量上限后重新分配内存,实测容量翻倍

// 切片长度扩张
func sliceLengthIncrease() {
	// 初始化时支持指定长度和容量,初始值为零值
	slice := make([]int, 3, 5)
	slice[1] = 1
	slice[2] = 2
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])
	for i := 4; i <= 6; i++ {
		// 追加到容量上限后重新分配内存,实测容量翻倍
		slice = append(slice, i)
		fmt.Println(i, " : ", slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])
	}
	fmt.Println()
}
[0 1 2] len 3 cap 5 pos 0xc00000c300
4  :  [0 1 2 4] len 4 cap 5 pos 0xc00000c300
5  :  [0 1 2 4 5] len 5 cap 5 pos 0xc00000c300
6  :  [0 1 2 4 5 6] len 6 cap 10 pos 0xc0000122d0

切片追加对底层数组的影响

对数组的左闭右开区间[L, R)切片。
在基于数组的切片中一次追加的单个或多个元素,可容纳时,影响底层数组;
不可可容纳时,重新分配空间,不影响底层数组。

// 切片扩张对底层数组的影响
func sliceInfluenceBaseArray() {
	array := [6]int{1, 2, 3, 4, 5, 6}
	fmt.Println(array, "pos", &array[1])

	// 左闭右开区间[L, R)切片
	slice := array[1:2]
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])

	// 在基于数组的切片中追加单个元素,影响底层数组
	slice = append(slice, 0)
	fmt.Println(array, &array[1])
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])

	// 在基于数组的切片中一次追加的多个元素,可容纳时,影响底层数组
	slice = append(slice, []int{9, 8}...)
	fmt.Println(array, &array[1])
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])

	// 在基于数组的切片中一次追加多个元素,不可可容纳时,重新分配空间,此次不影响底层数组
	slice = append(slice, []int{7, 6}...)
	fmt.Println(array, &array[1])
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])
	fmt.Println()
}
[1 2 3 4 5 6] pos 0xc00000c338
[2] len 1 cap 5 pos 0xc00000c338
[1 2 0 4 5 6] 0xc00000c338
[2 0] len 2 cap 5 pos 0xc00000c338
[1 2 0 9 8 6] 0xc00000c338
[2 0 9 8] len 4 cap 5 pos 0xc00000c338
[1 2 0 9 8 6] 0xc00000c338
[2 0 9 8 7 6] len 6 cap 10 pos 0xc000012320

[]byte []rune切片与string字符串

string 转换为 byte发生了复制。
内建函数append可以把string当作[]byte展开,无需转换。
但不能把stringObject…直接作为…byte参数。

func myAppend(slice []byte, elems ...byte) []byte {
	return append(slice, elems...)
}

// string 与 []byte 和 []rune
func sliceByteRuneString() {
	var str, str2 string
	str, str2 = "hello ", "世界"

	// string 转换为 byte发生了复制
	fmt.Println(str, "len", len(str), "pos", &str, "len", len([]byte(str)), "pos", &[]byte(str)[0],
		"len", len([]rune(str)), "pos", &[]rune(str)[0])
	fmt.Println(str2, "len", len(str2), "pos", &str2, "len", len([]byte(str2)), "pos", &[]byte(str2)[0],
		"len", len([]rune(str2)), "pos", &[]rune(str2)[0])

	// 内建函数append可以把string当作[]byte展开,无需转换
	byteSlice := append([]byte(str), str2...)
	fmt.Println(byteSlice, "len", len(byteSlice), "cap", cap(byteSlice))
	fmt.Println(string(byteSlice))

	// 但不能把stringObject...直接作为...byte参数
	// cannot use str2 (type string) as type []byte in argument to myAppend
	// byteSlice := myAppend([]byte(str), str2...)
	byteSlice = myAppend([]byte(str), []byte(str2)...)
	fmt.Println(byteSlice, "len", len(byteSlice), "cap", cap(byteSlice))
	fmt.Println(string(byteSlice))

	runeSlice := append([]rune(str), []rune(str2)...)
	fmt.Println(runeSlice, "len", len(runeSlice), "cap", cap(runeSlice))
	fmt.Println(string(runeSlice))
}
hello  len 6 pos 0xc00003a1f0 len 6 pos 0xc00000a1d0 len 6 pos 0xc000010400
世界 len 6 pos 0xc00003a200 len 6 pos 0xc00000a1d8 len 2 pos 0xc00000a1e0
[104 101 108 108 111 32 228 184 150 231 149 140] len 12 cap 16
hello 世界
0xc00000a218
[104 101 108 108 111 32 228 184 150 231 149 140] len 12 cap 16
hello 世界
[104 101 108 108 111 32 19990 30028] len 8 cap 8
hello 世界

完整代码

package main

import "fmt"

// 切片长度扩张
func sliceLengthIncrease() {
	// 初始化时支持指定长度和容量,初始值为零值
	slice := make([]int, 3, 5)
	slice[1] = 1
	slice[2] = 2
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])
	for i := 4; i <= 6; i++ {
		// 追加到容量上限后重新分配内存,实测容量翻倍
		slice = append(slice, i)
		fmt.Println(i, " : ", slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])
	}
	fmt.Println()
}

// 切片扩张对底层数组的影响
func sliceInfluenceBaseArray() {
	array := [6]int{1, 2, 3, 4, 5, 6}
	fmt.Println(array, "pos", &array[1])

	// 左闭右开区间[L, R)切片
	slice := array[1:2]
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])

	// 在基于数组的切片中追加单个元素,影响底层数组
	slice = append(slice, 0)
	fmt.Println(array, &array[1])
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])

	// 在基于数组的切片中一次追加的多个元素,可容纳时,影响底层数组
	slice = append(slice, []int{9, 8}...)
	fmt.Println(array, &array[1])
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])

	// 在基于数组的切片中一次追加多个元素,不可可容纳时,重新分配空间,此次不影响底层数组
	slice = append(slice, []int{7, 6}...)
	fmt.Println(array, &array[1])
	fmt.Println(slice, "len", len(slice), "cap", cap(slice), "pos", &slice[0])
	fmt.Println()
}

func myAppend(slice []byte, elems ...byte) []byte {
	return append(slice, elems...)
}

// string 与 []byte 和 []rune
func sliceByteRuneString() {
	var str, str2 string
	str, str2 = "hello ", "世界"

	// string 转换为 byte发生了复制
	fmt.Println(str, "len", len(str), "pos", &str, "len", len([]byte(str)), "pos", &[]byte(str)[0],
		"len", len([]rune(str)), "pos", &[]rune(str)[0])
	fmt.Println(str2, "len", len(str2), "pos", &str2, "len", len([]byte(str2)), "pos", &[]byte(str2)[0],
		"len", len([]rune(str2)), "pos", &[]rune(str2)[0])

	// 内建函数append可以把string当作[]byte展开,无需转换
	byteSlice := append([]byte(str), str2...)
	fmt.Println(byteSlice, "len", len(byteSlice), "cap", cap(byteSlice))
	fmt.Println(string(byteSlice))

	// 但不能把stringObject...直接作为...byte参数
	// cannot use str2 (type string) as type []byte in argument to myAppend
	// byteSlice := myAppend([]byte(str), str2...)
	byteSlice = myAppend([]byte(str), []byte(str2)...)
	fmt.Println(byteSlice, "len", len(byteSlice), "cap", cap(byteSlice))
	fmt.Println(string(byteSlice))

	runeSlice := append([]rune(str), []rune(str2)...)
	fmt.Println(runeSlice, "len", len(runeSlice), "cap", cap(runeSlice))
	fmt.Println(string(runeSlice))
}
func main() {
	sliceLengthIncrease()
	sliceInfluenceBaseArray()
	sliceByteRuneString()
}

(每次运行地址不同)

[0 1 2] len 3 cap 5 pos 0xc00000c300
4  :  [0 1 2 4] len 4 cap 5 pos 0xc00000c300
5  :  [0 1 2 4 5] len 5 cap 5 pos 0xc00000c300
6  :  [0 1 2 4 5 6] len 6 cap 10 pos 0xc0000122d0

[1 2 3 4 5 6] pos 0xc00000c338
[2] len 1 cap 5 pos 0xc00000c338
[1 2 0 4 5 6] 0xc00000c338
[2 0] len 2 cap 5 pos 0xc00000c338
[1 2 0 9 8 6] 0xc00000c338
[2 0 9 8] len 4 cap 5 pos 0xc00000c338
[1 2 0 9 8 6] 0xc00000c338
[2 0 9 8 7 6] len 6 cap 10 pos 0xc000012320

hello  len 6 pos 0xc00003a1f0 len 6 pos 0xc00000a1d0 len 6 pos 0xc000010400
世界 len 6 pos 0xc00003a200 len 6 pos 0xc00000a1d8 len 2 pos 0xc00000a1e0
[104 101 108 108 111 32 228 184 150 231 149 140] len 12 cap 16
hello 世界
0xc00000a218
[104 101 108 108 111 32 228 184 150 231 149 140] len 12 cap 16
hello 世界
[104 101 108 108 111 32 19990 30028] len 8 cap 8
hello 世界
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值