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中文网其他相关文章!