dsmlf1207915 2016-06-16 06:32
浏览 237
已采纳

如何在Go中复制接口值?

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
", user1.Name())

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

    fmt.Printf("User2's name: %s
", user2.Name()) // The name will be changed as "user2"
    fmt.Printf("User1's name: %s
", 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?

  • 写回答

2条回答 默认 最新

  • drc4925 2016-06-16 06:48
    关注

    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")
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 用hfss做微带贴片阵列天线的时候分析设置有问题
  • ¥50 我撰写的python爬虫爬不了 要爬的网址有反爬机制
  • ¥15 Centos / PETSc / PETGEM
  • ¥15 centos7.9 IPv6端口telnet和端口监控问题
  • ¥120 计算机网络的新校区组网设计
  • ¥20 完全没有学习过GAN,看了CSDN的一篇文章,里面有代码但是完全不知道如何操作
  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 海浪数据 南海地区海况数据,波浪数据
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等