Go 语言为什么建议 append 追加新元素使用原切片变量接收返回值?

开发 前端
在 Go 语言中,切片类型比较常用,将新元素追加到切片也比较常见,因此 Go 语言提供一个内置函数 append,该函数可以非常方便实现此功能。

​1.介绍

在 Go 语言中,切片类型比较常用,将新元素追加到切片也比较常见,因此 Go 语言提供一个内置函数 append,该函数可以非常方便实现此功能。

虽然 Go 语言内置函数 append 使用非常方便,但是使用不当会不小心掉入一些“坑”。

本文我们介绍一下 Go 语言为什么建议 append 追加新元素使用原切片变量接收返回值?

2.append 的“坑”

我们先看一段示例代码:

func main() {
a := make([]int, 0, 5)
a = append(a, 1)
b := append(a, 2)
c := append(a, 3)
fmt.Printf("v=%v || p=%p\n", a, &a)
fmt.Printf("v=%v || p=%p\n", b, &b)
fmt.Printf("v=%v || p=%p\n", c, &c)
}

阅读上面这段代码,我们定义一个长度为 0,容量为 5 的 int 类型的切片 a。

首先,我们使用 Go 语言内置函数 append​ 追加一个元素 1 到切片 a 中。

然后,我们使用 Go 语言内置函数 append​ 追加一个元素 2 到切片 a 中。

最后,我们使用 Go 语言内置函数 append​ 追加一个元素 3 到切片 a 中。

但是,我们在输出结果中发现,b 的输出结果不是 [1 2]​,c 的输出结果不是 [1 2 3]​,b 和 c 的实际输出结果相同,都是 [1 3]。为什么呢?我们接着往下看 Part 03 的内容。

3.append 的原理

Go 语言内置函数 append 第一个入参是切片类型的变量,而切片本身是一个 struct 结构,参数传递时会发生值拷贝。

Go 语言 slice 源码如下:

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

因为 Go 语言内置函数 append​ 参数是值传递,所以 append​ 函数在追加新元素到切片时,append 会生成一个新切片,并且将原切片的值拷贝到新切片。

在 Part 02 示例代码中,我们三次使用 append 参数追加新元素到切片 a 的操作,接收返回值的变量都不同。

第二次操作时,因为 append​ 生成一个新切片,将原切片 a 的值拷贝到新切片,并且将新元素在原切片a[len(a)]​ 长度的位置开始追加,使用变量 b 接收 append​ 返回值 [1 2]​,所以变量 b 的值是 [1 2]。

第三次操作时,同样 append​ 生成一个新切片,将原切片 a 的值拷贝到新切片,并且将新元素在原切片a[len(a)]​ 长度的位置开始追加,使用变量 c 接收 append​ 返回值 [1 3]​,所以变量 c 的值是 [1 3]。

但是,因为三个切片的底层数组相同,Go 内置函数 append 会在原切片长度的位置开始追加新元素,所以第三次操作时,把第二次操作时得到的变量 b 的最后一个元素覆盖了。

阅读到这里,相信聪明的读者朋友们已经明白 Part 02 示例代码为什么实际输出结果和预想的输出结果不同了吧。

4.总结

本文我们介绍 Go 语言中使用内置函数 append 追加新元素的一个“坑”,建议读者朋友们使用原切片变量接收返回值。

参考资料:

  • https://go.dev/tour/moretypes/15
  • https://pkg.go.dev/builtin#append
  • https://go.dev/blog/slices-intro
  • https://go.dev/doc/effective_go#slices
  • https://go.dev/ref/spec#Slice_types
  • https://go.dev/ref/spec#Length_and_capacity
  • https://go.dev/ref/spec#Making_slices_maps_and_channels
  • https://go.dev/ref/spec#Appending_and_copying_slices

责任编辑:武晓燕 来源: Golang语言开发栈
相关推荐

2023-12-27 08:12:04

切片Go语言

2022-09-18 23:09:13

Go语言标准库

2024-01-02 10:38:22

Go语言数组

2024-03-15 09:56:47

切片函数泛型

2021-08-13 11:31:23

HTTP

2023-03-06 08:01:25

structGo语言

2020-04-07 16:12:56

Go编程语言开发

2021-12-19 23:58:51

Golang语言返回值

2023-08-07 14:52:33

WindowsExplorer进程

2009-11-17 16:16:59

PHP递归函数

2020-06-23 14:09:49

枚举JDK场景

2012-08-20 09:16:15

Go语言

2012-08-13 09:15:54

Go开发语言编程语言

2016-09-27 21:25:08

Go语言Ken Thompso

2018-05-02 12:34:48

2024-03-11 11:02:03

Date类JavaAPI

2024-07-08 00:01:00

GPM模型调度器

2021-03-10 09:40:50

Linux命令文件

2010-07-20 11:37:00

Perl函数返回值

2023-04-03 08:02:16

切片扩容GO
点赞
收藏

51CTO技术栈公众号