在 Go 中复制接口值
Go 中的接口值封装了动态类型和底层具体值。将一个接口值分配给另一个接口值会复制底层值,而不是原始具体值本身。在使用接口和结构体指针时,这可能会导致意外行为。
考虑以下示例:
type User interface { Name() string SetName(name string) } type Admin struct { name string } func (a *Admin) Name() string { return a.name } func (a *Admin) SetName(name string) { a.name = name }
在此示例中,Admin 实现了 User 界面。我们创建一个 User 类型的 user1 变量,并使用指向 Admin 结构体的指针对其进行初始化。
var user1 User user1 = &Admin{name: "user1"}
现在,我们创建一个新的 user2 变量并将其分配给 user1 的值。
var user2 User user2 = user1
这里的问题是 user1 和 user2 都引用同一个 Admin 实例。更改 user2 的名称也会更改 user1 的名称。这是因为接口值仅包含指向底层 Admin 结构体的指针。
为了防止这种情况,我们需要为 user2 创建一个新的 Admin 结构体。我们可以使用反射来完成这个:
var user2 User padmin := user1.(*Admin) // Obtain *Admin pointer admin2 := *padmin // Make a copy of the Admin struct user2 = &admin2 // Wrap its address in another User
现在,更改 user2 的名称不再影响 user1。
但是,这个解决方案需要我们知道接口值的具体类型提前。更通用的解决方案是使用反射来创建接口值动态类型的新实例:
var user2 User if reflect.TypeOf(user1).Kind() == reflect.Ptr { // Pointer: user2 = reflect.New(reflect.ValueOf(user1).Elem().Type()).Interface().(User) } else { // Not pointer: user2 = reflect.New(reflect.TypeOf(user1)).Elem().Interface().(User) }
此解决方案适用于指针和非指针接口值。
以上是如何正确复制Go中的接口值以避免共享底层数据?的详细内容。更多信息请关注PHP中文网其他相关文章!