假設一個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
}
}
關鍵是, Golang<-- HERE編譯器是將 slice 元素的臨時副本復制到回圈的范圍內,還是就地獲取 slice 元素的地址?
這個想法是為了避免復制整個切片元素。
一個作業示例:https ://go.dev/play/p/jHOC2DauyrQ?v=goprev
uj5u.com熱心網友回復:
&sl[i]不復制 slice 元素,它只是計算i第 th 個元素的地址。
切片元素充當變數,并&x計算為變數的地址x。想一想:既然&sl[i]是i第th個元素的地址,這個地址既不需要也不用到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]運算式的評估)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/535732.html
標籤:去指针结构片
