Memory 如何在Go中表示接口?

Memory 如何在Go中表示接口?,memory,types,interface,go,Memory,Types,Interface,Go,我现在正在读两篇文章,有点困惑 这篇文章说 r示意性地包含(值,类型)对(tty,*os.File)。 注意,type*os.File实现的方法不是Read;即使 虽然接口值仅提供对读取方法的访问, 其中的值包含有关该值的所有类型信息 另一篇文章说 在我们的示例中,itable适用于Stringer holding类型二进制文件 列出用于满足Stringer的方法,Stringer只是字符串: 二进制的其他方法(Get)没有出现在itable中 感觉这两个人是对立的。根据第二篇文章,第一个摘录

我现在正在读两篇文章,有点困惑

这篇文章说

r示意性地包含(值,类型)对(tty,*os.File)。 注意,type*os.File实现的方法不是Read;即使 虽然接口值仅提供对读取方法的访问, 其中的值包含有关该值的所有类型信息

另一篇文章说

在我们的示例中,itable适用于Stringer holding类型二进制文件 列出用于满足Stringer的方法,Stringer只是字符串: 二进制的其他方法(Get)没有出现在itable中

感觉这两个人是对立的。根据第二篇文章,第一个摘录中的变量r应该是(tty,io.Reader),因为这是r的静态类型。相反,文章说*os.File是tty的类型。如果第二个示例是正确的,那么第一个示例中的图表应该包含由二进制类型实现的所有方法

我哪里做错了

两者都是正确的,r“holds”(tty,*os.File),这就是第二篇文章所说的。请注意,反射定律的层次更高,没有提到第二篇文章中讨论的实现细节(在每个版本中可能会更改)。第二篇文章的图表如下:“s包含示意图(b,*二进制)。s是Stringer类型,其数据是一个值为200的二进制,s的itable包含一个方法字符串,其他二进制(或*二进制)方法不在itable中表示,因此s无法访问


请注意,我认为Go 1.4中接口的实际实现与第二篇文章(Russ?)所述不同。”

这两篇文章在两个非常不同的粒度级别上解释了一个类似的概念。正如沃尔克所说,“反射定律”是对通过反射检查对象时实际发生的情况的基本概述。您的第二篇文章将研究接口的动态调度属性(也可以通过反射来解析),以及运行时如何在运行时解析它们

根据第二篇文章,第一个摘录中的变量r应该是(tty,io.Reader)

基于这种理解,可以将运行时的接口视为“包装器对象”。它的存在是为了提供关于另一个对象(第二篇文章中的
itable
)的信息,以便知道在包装对象布局中跳转到哪里(不同版本的实现可能不同..但对于大多数语言,原理基本相同)

这就是为什么在
r
上调用
Read
。。首先,它将检查
itable
并跳转到为
os.File
类型设置的函数。如果那是一个接口。。您将看到另一个解引用和调度(IIRC在Go中根本不适用)


RE:Reflection——你可以很容易地理解它,以
(值,类型)
对的形式(通过
reflect.ValueOf
reflect.TypeOf
方法)。

!目前它们是如何实施的?不知道。只要看一下来源。这是纯粹的开始。等等…所以我没有完全明白,但你是说他们指的是不同的东西吗?当第一篇文章说r HOLD(tty,*os.File)时,这与第二篇文章中提到的接口类型不一样吗?在铸造过程中会发生什么?是否有对新创建的itable的引用(这一定很简单,因为接口是一个轻量级包装器),我已经更新了我的答案。回答您关于新itables的问题:这一切都发生在编译时。因此,是的,您在施放时将有一个对新itable的引用。。但这不会完全发生在运行时。它们将在程序引导过程中设置(因为调度表在其他环境中)。
> var r io.Reader
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
    return nil, err
}
r = tty