Go 中介面值的深拷貝
直接在Go 中複製介面值會產生淺拷貝,表示對複製的內容進行更改值也會影響原始值。這是因為介面保存了對底層具體類型的引用。
名稱變更的原因
為了理解所提供程式碼中的問題,讓我們分析一下介面值的工作原理。使用者介面代表一個契約,管理員和使用者都實現這個契約。將 user1 指派給 user2 時,我們實際上是在建立對相同管理實例的參考。修改user2的Name()方法直接修改了共享的Admin實例,因此也改變了user1的名稱。
反射解決方案
要實現深拷貝,我們需要建立底層具體類型的新實例並將其包裝在新的使用者介面值中。實現此目的的一種方法是使用反射。我們可以使用reflect.ValueOf()和reflect.Elem()函數來取得儲存在user1中的底層值。然後,我們可以使用reflect.New()來建立相同類型的新實例,並使用reflect.MethodByName()來取得Name()方法。最後,我們可以在新實例上呼叫 SetName() 方法,並將其包裝在新的使用者介面值中。
func CloneUser(user User) User { val := reflect.ValueOf(user) if val.Kind() != reflect.Ptr { panic("expected pointer") } elem := val.Elem() t := elem.Type() newElem := reflect.New(t).Elem() newElem.MethodByName("SetName").Call([]reflect.Value{reflect.ValueOf(newElem.String())}) return newElem.Interface().(User) }
使用此函數,我們可以建立一個不影響原始實例的副本:
var user2 User = CloneUser(user1) user2.SetName("user2") fmt.Println(user1.Name(), user2.Name()) // Outputs: user1 user2
以上是Go中如何實現介面值的深拷貝?的詳細內容。更多資訊請關注PHP中文網其他相關文章!