首頁 >後端開發 >Golang >為什麼 Golang 的 `append()` 似乎在通過通道發送切片後修改它?

為什麼 Golang 的 `append()` 似乎在通過通道發送切片後修改它?

Linda Hamilton
Linda Hamilton原創
2024-11-02 10:01:31357瀏覽

Why Does Golang's `append()` Seem to Modify a Slice After It's Sent Over a Channel?

Golang的append()什麼時候會建立一個新的切片?

append()的文件表明它會分配一個新的切片並且當原始切片容量不足時,進行元素複製。但是,在檢查以下程式碼的輸出時會出現差異,該程式碼會產生布林字母表的組合。

<code class="go">package main

import (
    "fmt"
)

func AddOption(c chan []bool, combo []bool, length int) {
    if length == 0 {
        fmt.Println(combo, "!")
        c <- combo
        return
    }
    var newCombo []bool
    for _, ch := range []bool{true, false} {
        newCombo = append(combo, ch)
        AddOption(c, newCombo, length-1)
    }
}

func main() {
    c := make(chan []bool)
    go func(c chan []bool) {
        defer close(c)
        AddOption(c, []bool{}, 4)
    }(c)
    for combination := range c {
        fmt.Println(combination)
    }
}</code>

對比觀察

在輸出中,以感嘆號結尾的行表示AddOption 通過通道發送的切片,而沒有感嘆號的行表示main() 中接收的切片。值得注意的是,儘管append()據稱返回了一個新切片,但通過通道發送的切片似乎在發送後被修改。

檢查來源

有問題的程式碼區塊是:

<code class="go">var newCombo []bool
for _, ch := range []bool{true, false} {
    newCombo = append(combo, ch)
    AddOption(c, newCombo, length-1)
}</code>

根據文檔,當原始切片的容量不足時,append()應該傳回一個新的切片描述符,指向新的底層資料數組。但是,作為 AddOption 的第二個參數傳遞的值可以是指向切片描述符的指針,也可以是切片描述符的真實副本。

澄清行為

這個問題的答案在於區分切片資料類型和它的實際表示。切片描述子由長度和容量的兩個整數以及指向底層資料的指標組成。

雖然append()確實傳回一個帶有可能不同的底層資料數組的新切片描述符,但指向資料的指標除非容量擴大,否則保持不變。這意味著雖然切片描述符本身是副本,但指標值(底層資料的位址)是共用的。

其他範例

為了說明,請考慮這個程式碼片段:

<code class="go">package main

import "fmt"

func main() {
    s := make([]int, 0, 5)
    s = append(s, []int{1, 2, 3, 4}...)

    a := append(s, 5)
    fmt.Println(a)

    b := append(s, 6)
    fmt.Println(b)
    fmt.Println(a)
}</code>

此程式碼列印:

[1 2 3 4 5]
[1 2 3 4 6]
[1 2 3 4 6]

此程式碼列印:
[1 2 3 4 5]
[1 2 3 4 6]
[1 2 3 4 5]

最初,s有足夠的容量,因此a和b共享相同的底層資料指標。但是,如果我們將 s 的容量減少到 4,輸出將更改為:這表明只有當 s 有足夠的容量時,a 和 b 才會共享相同的底層數據。

以上是為什麼 Golang 的 `append()` 似乎在通過通道發送切片後修改它?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn