Go Append实现

本文深入探讨了Go语言中的切片操作,包括如何使用len()和cap()函数获取切片的长度和容量,以及如何通过自定义Append函数实现切片的高效扩展。通过实例演示了当切片长度加数据长度大于切片容量时,如何创建新切片并复制原有数据,最后通过循环将新数据追加到切片中。

切片(s)
len(s) 获取长度
cap(s) 获取容量
Append(s, d)实现时比较:len(s)+len(d) > cap(s)

package main

import (
	"fmt"
)

func main() {
	mySlice := make([]byte, 0, 0)
	data := []byte{1, 2, 3, 4, 5}

	mySlice = Append(mySlice, data)
	fmt.Printf("slice: %v\n", mySlice)
	//output: 'slice: [1 2 3 4 5]'
}

func Append(slice []byte, data []byte) []byte {
	sliLen := len(slice)
	needLen := len(slice) + len(data)

	if needLen > cap(slice) {
		//创建长度足够的新切片
		newSlice := make([]byte, needLen, needLen)
		//将数据复制到新的切片中
		copy(newSlice, slice)
		slice = newSlice
	}

	//重置切片长度---切片长度可能小于容量
	//若没有该步骤,若slice的长度小于容量时可能越界导致崩溃: 'panic: runtime error: index out of range'
	slice = slice[0:needLen]

	for i, c := range data {
		slice[sliLen+i] = c
	}
	return slice
}

### Golang 中 `append` 方法的使用方法 在 Golang 中,`append` 是一个内置函数,用于向切片(slice)追加元素。如果原始切片有足够的容量来容纳新增的元素,则直接在原切片的基础上扩展;否则,会创建一个新的底层数组,并将原切片和新元素复制到新数组中[^1]。 #### 1. 基本用法 以下是一个简单的示例,展示如何使用 `append` 向切片追加单个或多个元素: ```go package main import "fmt" func main() { a := []int{1, 2, 3} a = append(a, 4) // 追加单个元素 fmt.Println(a) // 输出: [1 2 3 4] a = append(a, 5, 6, 7) // 追加多个元素 fmt.Println(a) // 输出: [1 2 3 4 5 6 7] } ``` #### 2. 容量不足时的行为 当切片的容量不足以容纳新元素时,Golang 会分配一个新的底层数组,并将原切片的内容和新元素复制到新数组中。新数组的容量通常是原容量的两倍,但具体行为可能因实现而异[^1]。 以下代码展示了容量不足时的情况: ```go package main import "fmt" func main() { a := make([]int, 0, 2) // 初始长度为0,容量为2 fmt.Printf("len=%d, cap=%d\n", len(a), cap(a)) // 输出: len=0, cap=2 a = append(a, 1, 2) // 不需要扩容 fmt.Printf("len=%d, cap=%d\n", len(a), cap(a)) // 输出: len=2, cap=2 a = append(a, 3) // 需要扩容 fmt.Printf("len=%d, cap=%d\n", len(a), cap(a)) // 输出: len=3, cap=4 } ``` #### 3. 空切片的处理 即使切片是 `nil` 或长度为 0,也可以直接使用 `append` 函数向其追加元素。Golang 会自动初始化切片并分配适当的底层数组[^2]。 以下是一个示例: ```go package main import "fmt" func main() { var arr []int fmt.Printf("Before append: %v, len=%d, cap=%d\n", arr, len(arr), cap(arr)) // 输出: Before append: [], len=0, cap=0 arr = append(arr, 1, 2) fmt.Printf("After append: %v, len=%d, cap=%d\n", arr, len(arr), cap(arr)) // 输出: After append: [1 2], len=2, cap=2 } ``` #### 4. 子切片与 `append` 当对子切片调用 `append` 时,需要注意原切片和子切片共享同一个底层数组。如果 `append` 操作导致容量不足,则会创建新的底层数组,否则会影响原切片的内容[^1]。 以下是一个示例: ```go package main import "fmt" func main() { a := []int{1, 2, 3, 4} b := a[1:3] // 子切片 [2, 3] fmt.Println("Before append:", a, b) // 输出: Before append: [1 2 3 4] [2 3] b = append(b, 5) // 不需要扩容 fmt.Println("After append:", a, b) // 输出: After append: [1 2 3 5] [2 3 5] c := append(b, 6) // 需要扩容 fmt.Println("After append with capacity change:", a, b, c) // 输出: After append with capacity change: [1 2 3 5] [2 3 5] [2 3 5 6] } ``` #### 5. 性能注意事项 - 如果频繁调用 `append` 并且可以预估最终长度,建议预先分配足够的容量以减少内存分配次数。 - 在高并发场景下,注意切片的共享问题,避免数据竞争[^1]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值