2 回答

TA貢獻1840條經驗 獲得超5個贊
你可能對 Go 中切片的工作方式有一個錯誤的看法。
當您將元素附加到切片時,調用會append()返回一個新切片。如果沒有發生重新分配,兩個切片值——你調用的值append()和它返回的值——共享相同的后備數組,但它們的長度不同;觀察:
package main
import "fmt"
func main() {
a := make([]int, 0, 10)
b := append(a, 1, 2, 3)
c := append(a, 4, 3, 2)
fmt.Printf("a=%#v\nb=%#v\nc=%#v\n", a, b, c)
}
輸出:
a=[]int{}
b=[]int{4, 3, 2}
c=[]int{4, 3, 2}
所以, len(a) == 0, len(b) == 3, len(c) == 3, 和第二次調用append()owerw 寫了第一個所做的事情,因為所有的切片共享相同的底層數組。
關于后備數組的重新分配,規范很明確:
如果 s 的容量不足以容納附加值,則 append 分配一個新的、足夠大的底層數組,該數組既適合現有切片元素又適合其他值。否則, append 會重新使用底層數組。
由此可知:
append()
如果被附加到的切片的容量足夠,則永遠不要復制底層存儲。如果沒有足夠的容量,陣列將被重新分配。
也就是說,給定一個s
要向其附加N
元素的切片,如果 iff 則不會進行重新分配cap(s) - len(s) ≥ N
。
因此,我懷疑您的問題不在于意外的重新分配結果,而在于 Go 中實現的切片概念。要吸收的代碼想法是append()
返回結果切片值,除非您完全了解影響,否則您應該在調用后使用該值。
我建議從這里開始以完全理解它們。

TA貢獻1806條經驗 獲得超5個贊
因此,控制內存分配的解決方案是明確地進行(這讓我想起 Go 比其他(腳本)語言更像是一種系統語言):
package main
import (
"fmt"
)
func main() {
a1 := make([][]int, 3)
a2 := make([][]int, 3)
b := [][]int{{1, 1, 1}, {2, 2, 2}, {3, 3, 3}}
common1 := make([]int, 0)
common2 := make([]int, 0, 12) // provide sufficient capacity
common1 = append(common1, []int{10, 20}...)
common2 = append(common2, []int{10, 20}...)
idx := 0
for _, k := range b {
a1[idx] = append(common1, k...) // new slice is allocated
a2[idx] = make([]int, len(common2), len(common2)+len(k))
copy(a2[idx], common2) // copy & append could probably be
a2[idx] = append(a2[idx], k...) // combined into a single copy step
idx++
}
fmt.Println(a1)
fmt.Println(a2)
}
輸出:
[[10 20 1 1 1] [10 20 2 2 2] [10 20 3 3 3]]
[[10 20 1 1 1] [10 20 2 2 2] [10 20 3 3 3]]
https://play.golang.org/p/Id_wSZwb84
- 2 回答
- 0 關注
- 198 瀏覽
添加回答
舉報