亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

獲取切片元素的地址是否意味著 Go 中元素的副本?

獲取切片元素的地址是否意味著 Go 中元素的副本?

Go
絕地無雙 2023-03-15 15:00:03
假設一個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])。


查看完整回答
反對 回復 2023-03-15
  • 1 回答
  • 0 關注
  • 135 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號