假設一個Go 1.18程序有一個相當重的 struct,為此復制被認為是昂貴的:type MyStruct struct { P string // a lot of properties}現在讓我們定義一個函數,將這些元素的切片作為輸入參數,其目標是更新每個切片元素的屬性:func myFunc(sl []MyStruct) { for i := range sl { p := &sl[i] // <-- HERE p.P = "bar" // other properties mutations }}關鍵是<-- HERE,Golang 編譯器是將slice 元素的臨時副本復制到循環的范圍內,還是就地獲取 slice 元素的地址?這個想法是為了避免復制整個切片元素。一個工作示例:https://go.dev/play/p/jHOC2DauyrQ ?v=goprev
1 回答

森欄
TA貢獻1810條經驗 獲得超5個贊
&sl[i]
i
不復制 slice 元素,它只是計算第th 個元素的地址。
切片元素充當變量,并&x
計算為變量的地址x
。想一想:既然&sl[i]
是第th個元素的地址i
,這個地址既不需要也不用到struct的值,為什么還要復制呢?
如果你的切片太大以至于你擔心(隱式)副本的性能影響,你真的應該首先考慮在切片中存儲指針,這樣你就可以使你的循環和訪問元素變得更加簡單,而無需擔心副本:
func myFunc(sl []*MyStruct) {
? ? for _, v := range sl {
? ? ? ? v.P = "bar"
? ? ? ? // other properties mutations
? ? }
}
另請注意,如果您的切片包含非指針,并且您想要更改切片元素的字段,則索引切片并引用該字段也不涉及復制結構元素:
func myFunc(sl []MyStruct) {
? ? for i := range sl {
? ? ? ? sl[i].P = "bar"
? ? ? ? // other properties mutations
? ? }
}
是的,如果您必須修改多個字段,這可能會更冗長并且效率可能更低(但編譯器也可能識別并優化多個表達式的評估sl[i])。
- 1 回答
- 0 關注
- 135 瀏覽
添加回答
舉報
0/150
提交
取消