Day3 理解 golang slice 用法及原理 III

前两篇写了 slice 是什麽,以及创建 slice 的基本语法。

这篇就来写 slice 的参数传递以及 append 到底做了什麽。

Slice 的参数传递

func pass(arr []int) {
    arr[0] = 4
}
a := []int{1, 2, 3}
pass(a)

看了这段程序,我们都知道 slice 的第一个元素被改为 4 了。

这时候就会有人说 slice 是 pass by refernece,但是 go 只有 pass by value,还记得 Day1 理解 golang slice 用法及原理 I 所说的 slice header 吗,其实这个函式传递的是 slice header 的副本。slice 的第一个元素被更动,是因为两个 slice header 指向了共同的 underying array。

看图


再看一段程序

func pass(arr []int) {
    arr = []int{4, 5, 6}
}
a := []int{1, 2, 3}
pass(a)

arr 的更改并不会影响 a 的内容,因为两个 slice header 指向不同的 underlying array


如果想让 a 指向不同的 underyling array,应该要传送 slice header 的地址。

func pass(arr *[]int) {
    arr = []int{4, 5, 6}
}
a := []int{1, 2, 3}
pass(&a)

append 做了什麽

先看一些两个基本语法

将一个元素放进 slice 的最後一个元素

s := []int{1, 2, 3}
s = append(s, 1)

连接两个 slice 的内容

s1 := []int{1, 2, 3}
s2 := []int{4, 5, 6}
s1 = append(s1, s2...)

简单的一个问题, slice 在 append 过後还指向同一个 underlying array 吗? 还是分配了一块新的?

在回答问题之前,先了解一下 append 的实作概念,Reference 1 给了一个很好的概念范例,这段范例给出了 append 设计的想法 (注意:这只是设计的概念)。(如果不熟 copy 怎麽使用,自己 google 一下罗)

func Append(slice []int, elements ...int) []int {
    n := len(slice)
    total := len(slice) + len(elements)
    if total > cap(slice) {
        // Reallocate. Grow to 1.5 times the new size, so we can still grow.
        newSize := total*3/2 + 1
        newSlice := make([]int, total, newSize)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[:total]
    copy(slice[n:], elements)
    return slice
}

还记得 Day2 理解 golang slice 用法及原理 II 矿泉水的例子吗,假设想把两瓶水装成一瓶,如果本来瓶子容量够大,把另一瓶水装进来就好。如果装不下,那就去找更大的瓶子,把这两瓶水装进去罗。至於为什麽乘 3 除 2 ,那不重要,这边想表达的意思就是要找比原来两个 slice 加起来还要大的容量。

懂了之後,回答原本的问题就很简单了,答案是不一定。

文章索引

Reference

  1. Arrays, slices (and strings): The mechanics of 'append'

<<:  [Day2]PHP的资料型态02

>>:  LeetCode 解题 Day 03

Day08 测试写起乃-关於测试如何清除test db资料? & 安装 Database Cleaner

在测试这项范例之前我一直搞不懂在过去测试的时候我记得 test db 不会清除资料,後来查资料才发现...

Day 11 号志如何使用-等待与号志同步

号志的操作主要分成四种,我们就做个简单的说明: 1.创建跟删除号志:主要分成create/delet...

#10 实作篇 — 使用 SWR 抓取和 Cache 资料

嗨大家!昨天跟大家分享一个 library 叫做 SWR,文章在这里~ 今天用 SWR 新增了小功能...

Youtube Analytics API 教学 - 请出示身分 Python OAuth 2.0

「鲑鱼均,因为一场鲑鱼之乱被主管称为鲑鱼世代,广义来说以年龄和脸蛋分类的话这应该算是一种 KNN 的...

013-状态

到今天最大的困难,好像变成了想主题要写什麽。 来介绍一下做出一个元件後,基本上可以衍伸的思考可能会有...