在Go语言中,在结构体中使用接口

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

Using an interface within a struct in Go

问题

在尝试理解Go语言时,我在websocket.go中遇到了这段代码(已剪辑):

type frameHandler interface {
    HandleFrame(frame frameReader) (r frameReader, err error)
    WriteClose(status int) (err error)
}

// Conn代表一个WebSocket连接。
type Conn struct {
    config  *Config
    request *http.Request
    .
    .
    frameHandler
    PayloadType        byte
    defaultCloseStatus int
}

在Conn类型中,frameHandler独自存在?一个没有名称的接口?
在代码的后面,他们甚至尝试检查这个可怜的接口是否为nil:

Conn(a).frameHandler == nil

我个人的猜测是,结构体中的frameHandler是一个与frameHandler接口匹配的类型,并且还将具有名称frameHandler。这个猜测正确吗?呵呵,不管怎样,这是一个有趣的语言。

英文:

In trying to understand Go, I ran into this piece of code in websocket.go (snipped):

type frameHandler interface {
    HandleFrame(frame frameReader) (r frameReader, err error)
    WriteClose(status int) (err error)
}

// Conn represents a WebSocket connection.
type Conn struct {
    config  *Config
    request *http.Request
    .
    .
    frameHandler
    PayloadType        byte
    defaultCloseStatus int
}

In the Conn type the frameHandler stands there all alone? An interface without a name?
Later on in the code they even try check if the poor interface is nil:

Conn(a).frameHandler == nil

My own guess is that the frameHandler within the struct is a type which matches the frameHandler interface, and on top of that will have the name frameHandler. Is this correct? Hehe, fun language anyhow.

答案1

得分: 11

这一行:

    frameHandler

大致等同于这个:

    frameHandler frameHandler

其中frameHandler既是字段的名称,也是它的类型。此外,它将frameHandler的所有字段和方法添加到Conn中,所以如果conn是一个Conn,那么conn.WriteClose(0)意味着conn.frameHandler.WriteClose(0)

正如Go编程语言规范所述:

> 声明了一个类型但没有显式字段名的字段是一个<i>匿名字段</i>(俗称嵌入字段)。这样的字段类型必须指定为类型名<code>T</code>或非接口类型名的指针<code>*T</code>,而<code>T</code>本身不能是指针类型。未限定的类型名充当字段名。<pre>// 一个具有四个匿名字段T1、T2、P.T3和P.T4的结构体
struct {
T1 // 字段名为T1
T2 // 字段名为T2
P.T3 // 字段名为T3
P.T4 // 字段名为T4
x, y int // 字段名为x和y
}</pre> 下面的声明是非法的,因为字段名在结构体类型中必须是唯一的:<pre>struct {
T // 与匿名字段
T和
P.T冲突
T // 与匿名字段T和P.T冲突
P.T // 与匿名字段T和T冲突
}</pre> 匿名字段的字段和方法(§<a href="#Method_declarations">方法声明</a>)被提升为结构体的普通字段和方法(§<a href="#Selectors">选择器</a>)。对于一个名为<code>S</code>的结构体类型和一个名为<code>T</code>的类型,以下规则适用:<ul>
<li>如果<code>S</code>包含一个匿名字段<code>T</code>,则<code>S</code>的<a href="#Method_sets">方法集</a>包括<code>T</code>的方法集。
</li>
<li>如果<code>S</code>包含一个匿名字段<code>*T</code>,则<code>S</code>的方法集包括<code>*T</code>的方法集(它本身包括<code>T</code>的方法集)。
</li>
<li>如果<code>S</code>包含一个匿名字段<code>T</code>或<code>*T</code>,则<code>*S</code>的方法集包括<code>*T</code>的方法集(它本身包括<code>T</code>的方法集)。
</li>
</ul> 字段声明后可以跟一个可选的字符串字面量<i>标签</i>,它成为相应字段声明中所有字段的属性。这些标签通过<a href="#Package_unsafe">反射接口</a>可见,但在其他情况下被忽略。<pre>// 与TimeStamp协议缓冲区对应的结构体。
// 标签字符串定义了协议缓冲区字段的编号。
struct {
microsec uint64 "field 1"
serverIP6 uint64 "field 2"
process string "field 3"
}</pre>

英文:

This line:

    frameHandler

is roughly equivalent to this:

    frameHandler frameHandler

in that frameHandler is both the name of the field and its type. In addition, it adds all the fields and methods of the frameHandler to the Conn, so if conn is a Conn, then conn.WriteClose(0) means conn.frameHandler.WriteClose(0).

As the Go Programming Language Specification puts it:

> A field declared with a type but no explicit field name is an <i>anonymous field</i> (colloquially called an embedded field). Such a field type must be specified as a type name <code>T</code> or as a pointer to a non-interface type name <code>*T</code>, and <code>T</code> itself may not be a pointer type. The unqualified type name acts as the field name. <pre>// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
struct {
T1 // field name is T1
*T2 // field name is T2
P.T3 // field name is T3
*P.T4 // field name is T4
x, y int // field names are x and y
}</pre> The following declaration is illegal because field names must be unique in a struct type: <pre>struct {
T // conflicts with anonymous field *T and *P.T
*T // conflicts with anonymous field T and *P.T
*P.T // conflicts with anonymous field T and *T
}</pre> Fields and methods (§<a href="#Method_declarations">Method declarations</a>) of an anonymous field are promoted to be ordinary fields and methods of the struct (§<a href="#Selectors">Selectors</a>). The following rules apply for a struct type named <code>S</code> and a type named <code>T</code>: <ul>
<li>If <code>S</code> contains an anonymous field <code>T</code>, the
<a href="#Method_sets">method set</a> of <code>S</code> includes the
method set of <code>T</code>.
</li>
<li>If <code>S</code> contains an anonymous field <code>*T</code>, the
method set of <code>S</code> includes the method set of <code>*T</code>
(which itself includes the method set of <code>T</code>).
</li>
<li>If <code>S</code> contains an anonymous field <code>T</code> or
<code>*T</code>, the method set of <code>*S</code> includes the
method set of <code>*T</code> (which itself includes the method
set of <code>T</code>).
</li>
</ul> A field declaration may be followed by an optional string literal <i>tag</i>, which becomes an attribute for all the fields in the corresponding field declaration. The tags are made visible through a <a href="#Package_unsafe">reflection interface</a> but are otherwise ignored. <pre>// A struct corresponding to the TimeStamp protocol buffer.
// The tag strings define the protocol buffer field numbers.
struct {
microsec uint64 "field 1"
serverIP6 uint64 "field 2"
process string "field 3"
}</pre>

huangapple
  • 本文由 发表于 2012年2月23日 20:41:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/9413281.html
匿名

发表评论

匿名网友

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

确定