【问题标题】:Does assigning value to interface copy anything?为接口赋值会复制任何东西吗?
【发布时间】:2014-01-02 00:39:29
【问题描述】:

我一直在尝试围绕 Go 中的接口概念展开思考。阅读thisthis 帮助很大。

唯一让我不舒服的是语法。看看下面的the example

package main

import "fmt"

type Interface interface {
    String() string
}

type Implementation int

func (v Implementation) String() string {
    return fmt.Sprintf("Hello %d", v)
}

func main() {
    var i Interface
    impl := Implementation(42)
    i = impl
    fmt.Println(i.String())
}

我的问题是i = impl。基于接口实例实际上持有对实际数据的指针引用这一事实,我觉得这样做i = &impl 会更自然。通常在不使用& 时分配非指针会生成数据的完整内存副本,但是当分配给接口时,这似乎回避了这一点,而是简单地(在幕后)将指针分配给接口值。我说的对吗?也就是说,int(42) 的数据不会复制到内存中?

【问题讨论】:

    标签: go


    【解决方案1】:

    int(42) 的数据被复制。试试这个代码:

    func main() {
        var i Interface
        impl := Implementation(42)
        i = impl
        fmt.Println(i.String())
        impl = Implementation(91)
        fmt.Println(i.String())
    }
    

    (Playground link)

    您会发现第二个i.String() 仍然显示42。也许 Go 比较棘手的方面之一是方法接收器也可以是指针。

    func (v *Implementation) String() string {
        return fmt.Sprintf("Hello %d", *v)
    }
    
    // ...
    i = &impl
    

    如果您希望接口保存指向impl 原始值的指针,这就是您想要的。 “在幕后”,接口是一个结构,它要么保存指向某些数据的指针,要么保存数据本身(以及我们可以出于我们的目的忽略的某些类型元数据)。如果数据的大小小于或等于一个机器字,则数据本身会被存储——无论它是指针、结构还是其他值。

    否则它将是指向某些数据的指针,但这里有一个棘手的部分:如果实现接口的类型是结构,则指针将指向 结构的副本,而不是分配的结构到接口变量本身。或者至少在语义上用户可以这样认为,优化可能允许值在两个分歧之前不被复制(例如,直到您调用 String 或重新分配 impl)。

    简而言之:分配给接口在语义上可以被认为是实现接口的数据的副本。如果这是一个指向类型的指针,它复制指针,如果它是一个大结构,它复制大结构。在后台使用指针的接口的细节是出于垃圾收集和确保堆栈以可预测的数量扩展的原因。就开发人员而言,它们应该被视为所分配的实现类型的特定实例的语义副本。

    【讨论】:

    猜你喜欢
    • 2017-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 1970-01-01
    相关资源
    最近更新 更多