如何在Go中复制界面值? [英] How to copy an interface value in Go?

查看:96
本文介绍了如何在Go中复制界面值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在Go中复制界面值?



我的用户界面:

 类型用户界面{
Name()字符串
SetName(名称字符串)
}

我的管理员结构:

 类型管理结构{
名称字符串
}

func(a * Admin)Name()string {
返回a.name
}

func(a * Admin)SetName(name string){
a.name = name
}

我尝试复制 user1 的值。


$ b $主要功能:

$ p $ func main(){
var user1用户
user1 =& Admin {name:user1}

fmt.Printf(User1's name:%s\\\
,user1.Name())

var user2 User
user2 = user1
user2.SetName(user2)

fmt.Printf(User2的名称:%s\,user2。 Name())//名称将更改为user2
fmt.Printf(User1名称:%s \ n,user1.Name())//名称也会更改为user2,如何让user1名称不变?

如何实现更改副本名称的原始内容不变?

解决方案

这里的问题是你的 user1 变量(它的类型是 User )将一个指针保存到 Admin 结构中。

user1 分配给另一个变量(类型为 User ),将复制一对动态类型和值(value; type)的接口值 - 这样指针将被复制,它将指向同样的 Admin 结构。所以你只有一个 Admin 结构值,它们都是 user1 user2 参照(指向)这一点。通过任何接口值更改它将更改唯一的值。



使 user1 user2 distinct,你需要2个底层 Admin 结构。



一种方法是键入断言 user1 接口值,并复制该结构,并将其地址包含在另一个 User 值中:

  var user2 User 
padmin:= user1。(* Admin)//获取*管理指针
admin2:= * padmin //制作Admin结构的副本
user2 =& admin2 //将地址封装在另一个用户
user2.SetName(user2)

现在他们将会有所不同,输出(在 Go Playground ):

  User1的名称:user1 
User2的名称:user2
User1的名称:user1

当然这个解决方案有其局限性:存储在 User 接口值在解决方案中是有线的( * Admin )。



h3>

如果我们想要一个通用解决方案(不只是与 * Admin 一起工作的解决方案),我们可以使用反射 反映 包)。



为简单起见,我们假设 user1 总是包含一个指针(现在)。

<使用反射,我们可以得到动态类型(这里 * Admin ),甚至没有指针的动态类型( Admin )。我们可以使用 reflect.New() 来获取指向该类型的新值的指针(其类型将与 user1 - * Admin中的原始动态类型相同) code>),并将其换回到 User 中。这是它的样子:

pre $ var $ user $ b $ user3 = reflect.New ).Elem().Type())。Interface()。(User)
user3.SetName(user3)

输出(在去操场上试试这个):

  User1的名称:user1 
User3的名称:user3
User1的名称:user1

请注意, reflect.New()会创建一个新值,并初始化到零值(所以它不会是原件的副本)。这不是一个问题,因为 Admin 只有一个我们即将改变的字段,但一定要记住。



我们最初的假设是 user1 包含一个指针。现在完整解决方案不能做出这样的假设。如果 user1 中的值不是指针,那么它就是如何被克隆的:

  var user3 User 
如果reflect.TypeOf(user1).Kind()== reflect.Ptr {
//指针:
user3 = reflect.New反射.ValueOf(user1).Elem().Type())。接口()。(用户)
} else {
//非指针:
user3 = reflect.New(反射(用户)
}
user3.SetName(user3)


How to copy an interface value in Go?

My User interface:

type User interface {
    Name() string
    SetName(name string)
}

My Admin struct:

type Admin struct {
    name string
}

func (a *Admin) Name() string {
    return a.name
}

func (a *Admin) SetName(name string) {
    a.name = name
}

I try to copy user1's value.

Main Function:

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?
}

How to achieve that changing the copy's name the original doesn't change?

解决方案

The problem here is that your user1 variable (which is of type User) holds a pointer to an Admin struct.

When you assign user1 to another variable (of type User), the interface value which is a pair of the dynamic type and value (value;type) will be copied - so the pointer will be copied which will point to the same Admin struct. So you only have one Admin struct value, both user1 and user2 refer (point) to this. Changing it through any of the interface values changes the one and only value.

To make user1 and user2 distinct, you need 2 "underlying" Admin structs.

One way is to type assert the value in the user1 interface value, and make a copy of that struct, and wrap its address in another User value:

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")

Now they will be distinct, output (try it on the Go Playground):

User1's name: user1
User2's name: user2
User1's name: user1

Of course this solution has its limitation: the dynamic type stored in the User interface value is "wired" in the solution (*Admin).

Using reflection

If we want a "general" solution (not just one that works with *Admin), we can use reflection (reflect package).

For simplicity let's assume user1 always contains a pointer (for now).

Using reflection we can get the dynamic type (here *Admin), and even the dynamic type without a pointer (Admin). And we can use reflect.New() to obtain a pointer to a new value of that type (whose type will be identical to the original dynamic type in user1 - *Admin), and wrap this back into a User. This is how it could look like:

var user3 User
user3 = reflect.New(reflect.ValueOf(user1).Elem().Type()).Interface().(User)
user3.SetName("user3")

Output (try this one on the Go Playground):

User1's name: user1
User3's name: user3
User1's name: user1

Note that reflect.New() will create a new value which is initialized to its zero value (so it will not be a copy of the original). It's not a problem here as Admin only has one field which we're about to change anyway, but must be kept on our mind in general.

Our initial assumption was that user1 contains a pointer. Now the "full" solution must not make such assumption. If the value in user1 would not be a pointer, this is how it could be "cloned":

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中复制界面值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆