如何在 Go 中复制接口(interface)值?
我的用户
界面:
type User interface {
Name() string
SetName(name string)
}
我的 Admin
结构:
type Admin struct {
name string
}
func (a *Admin) Name() string {
return a.name
}
func (a *Admin) SetName(name string) {
a.name = name
}
我尝试复制 user1
的值。
主要功能:
func main() {
var user1 User
user1 = &Admin{name:"user1"}
fmt.Printf("User1's name: %s\n", user1.Name())
var user2 User
user2 = user1
user2.SetName("user2")
fmt.Printf("User2's name: %s\n", user2.Name()) // The name will be changed as "user2"
fmt.Printf("User1's name: %s\n", user1.Name()) // The name will be changed as "user2" too, How to make the user1 name does not change?
}
如何实现改名原件不改?
最佳答案
这里的问题是你的 user1
变量(属于 User
类型)包含一个指向 Admin
的指针结构。
当您分配 user1
时到另一个变量(类型 User
),接口(interface)值是一对动态类型和值 (value;type)
将被复制 - 所以指针将被复制,指向相同的 Admin
结构。所以你只有一个 Admin
结构值,两者都是 user1
和 user2
引用(指向)这个。通过任何接口(interface)值更改它会更改唯一值。
制作user1
和 user2
不同,你需要 2 个“底层”Admin
结构。
一种方法是type assert user1
中的值接口(interface)值,并复制该结构,并将其地址包装在另一个 User
中值:
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.SetName("user2")
现在它们将是不同的,输出(在 Go Playground 上尝试):
User1's name: user1
User2's name: user2
User1's name: user1
当然这个解决方案有其局限性:存储在 User
中的动态类型接口(interface)值在解决方案中是“有线的”(*Admin
)。
使用反射
如果我们想要一个“通用”解决方案(不只是使用 *Admin
的解决方案),我们可以使用反射( reflect
包)。
为简单起见,我们假设 user1
始终包含一个指针(目前)。
使用反射我们可以获得动态类型(这里是*Admin
),甚至是没有指针的动态类型(Admin
)。我们可以使用 reflect.New()
获取指向该类型新值的指针(其类型将与 user1
中的原始动态类型相同 - *Admin
),并将其包装回 User
中.这就是它的样子:
var user3 User
user3 = reflect.New(reflect.ValueOf(user1).Elem().Type()).Interface().(User)
user3.SetName("user3")
输出(在 Go Playground 上试试这个):
User1's name: user1
User3's name: user3
User1's name: user1
请注意 reflect.New()
将创建一个初始化为其零值的新值(因此它不会是原始值的副本)。这不是问题 Admin
只有一个字段我们将要更改,但总体上必须牢记在心。
我们最初的假设是 user1
包含一个指针。现在“完整”解决方案不能做出这样的假设。如果 user1
中的值不会是一个指针,这就是它可以被“克隆”的方式:
var user3 User
if reflect.TypeOf(user1).Kind() == reflect.Ptr {
// Pointer:
user3 = reflect.New(reflect.ValueOf(user1).Elem().Type()).Interface().(User)
} else {
// Not pointer:
user3 = reflect.New(reflect.TypeOf(user1)).Elem().Interface().(User)
}
user3.SetName("user3")
关于go - 如何在 Go 中复制接口(interface)值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37851500/