How are interfaces represented in Go?

huangapple go评论87阅读模式
英文:

How are interfaces represented in Go?

问题

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

这篇文章 - http://blog.golang.org/laws-of-reflection

var r io.Reader
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
    return nil, err
}
r = tty

r 包含了(值,类型)对,(tty, *os.File)。
注意,类型 *os.File 实现了除 Read 之外的其他方法;尽管接口值只提供对 Read 方法的访问,但内部的值携带了关于该值的所有类型信息。

另一篇文章说

就我们的例子而言,持有类型 Binary 的 Stringer 的 itable 列出了用于满足 Stringer 的方法,即只有 String 方法:
Binary 的其他方法(Get)在 itable 中没有出现。

How are interfaces represented in Go?

感觉这两篇文章是相互矛盾的。根据第二篇文章,第一个摘录中的变量 r 应该是 (tty, io.Reader),因为那是 r 的静态类型。然而,文章却说 *os.File 是 tty 的类型。如果第二个例子是正确的,那么第一个例子中的图表应该包含 Binary 类型实现的所有方法。

我错在哪里?

英文:

I'm reading through two articles right now and am a little confused.

This article - http://blog.golang.org/laws-of-reflection says

> var r io.Reader
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
    return nil, err
}
r = tty

> r contains, schematically, the (value, type) pair, (tty, *os.File).
> Notice that the type *os.File implements methods other than Read; even
> though the interface value provides access only to the Read method,
> the value inside carries all the type information about that value.

This other article, says

> In terms of our example, the itable for Stringer holding type Binary
> lists the methods used to satisfy Stringer, which is just String:
> Binary's other methods (Get) make no appearance in the itable.

How are interfaces represented in Go?

It feels like these two are in opposition. According to the second article, the variable r in the first extract should be (tty, io.Reader), as that is the static type of r. Instead, the article says that *os.File is the type of tty. If the second example were right, then the diagram in the first example should have all of the methods implemented by the Binary type.

Where am I going wrong?

答案1

得分: 3

这两篇文章在不同的层次上解释了一个相似的概念。正如Volker所说,“反射定律”是一个关于当你通过反射来检查对象时实际上发生了什么的基本概述。你的第二篇文章则研究了接口的动态分派属性(同样可以通过反射来解析),以及运行时如何在运行时解析它们。

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

这就是为什么在r上调用Read方法有效的原因。首先,它会检查itable并跳转到为os.File类型设置的函数。如果那是一个接口的话,你将会看到另一个解引用和分派(在Go中我记得根本不适用)。

关于反射 - 你可以通过reflect.ValueOfreflect.TypeOf方法获得一个易于理解的表示形式,即(value, type)对。

英文:

The two articles are explaining a similar concept at two very different levels of granularity. As Volker said, "Laws of Reflection" is a basic overview of what is actually happening when you examine objects via reflection. Your second article is examining the dynamic dispatch properties of an interface (which, can be resolved via reflection as well) and how the runtime resolves them at runtime.

> According to the second article, the variable r in the first extract should be (tty, io.Reader)

Given that understanding, think of an interface at runtime as a "wrapper object". It exists to provide information about another object (the itable from your second article) to know where to jump to in the wrapped objects layout (implementation may differ between versions .. but the principle is basically the same for most languages).

This is why calling Read on r works .. first it will check the itable and jump to the function that is laid out for the os.File type. If that was an interface .. you would be looking at another dereference and dispatch (which IIRC isn't applicable at all in Go).

RE: Reflection - you're getting an easily digestible representation of this, in the form of a (value, type) pair (via the reflect.ValueOf and reflect.TypeOf methods).

答案2

得分: 1

两种说法都是正确的,r "holds" (tty, *os.File),这是第二篇文章所说的。请注意,《反射定律》这篇文章更加高层次,没有提及实现细节(这些细节可能在每个版本中都会改变),就像第二篇文章中所讨论的那样。第二篇文章的图示如下所示:"s包含了示意图中的(b, Binary)。s的类型是Stringer,它的数据是一个值为200的Binary,s的itable包含了一个String方法,而Binary(或Binary)的其他方法没有在itable中表示,因此对于s来说是不可访问的。

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

英文:

Both are correct, r "holds" (tty, *os.File) and that is what the second article says. Note that Laws of Reflection is a bit more high-level and does not mention implementation details (which might change in each release) like discussed in the second article. The diagram of the second article read as follows: "s contains schematically (b, *Binary). s is of type Stringer, its data is a Binary with value 200 and s's itable contains one method String and the other methods of Binary (or *Binary) are not represented in the itable and thus not accessible for s.

Note that I think the actual implementation of interfaces in Go 1.4 is different from what the second article (Russ's?) states. "

huangapple
  • 本文由 发表于 2015年3月17日 05:40:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/29087450.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定