【问题标题】:Are there official words about what type is an interface type in Go?关于 Go 中的接口类型是什么类型的官方说法?
【发布时间】:2019-08-22 16:25:21
【问题描述】:

这是一道 Go 语法问题,似乎是一个愚蠢的问题,但我一直在检查 Go language specification 以找到一些官方词汇或定义来定义什么类型是 xxx 类型,比如,什么类型是接口类型?

例如,我看到这样的词:

接口类型的方法集就是它的接口。

或者

必须将嵌入字段指定为类型名称 T 或指向非接口类型名称 *T 的指针,并且 T 本身可能不是指针类型.

或者

考虑结构类型 T 有两种方法...

type T struct {
  a int
}
....

struct {...} 这样的类型文字是结构类型,那么Atype A struct {...}Btype B interface{...}A 是结构类型,B 是接口类型吗?

是的,从上面的结构类型T 的示例中,我可以看出给定类型是结构类型或接口类型的定义类型(通过“类型”声明)也是结构或接口类型。所以A 是一个结构类型,B 也是一个接口类型。但是这条规则的官方定义在哪里?

对于已定义的类型,我只能找到与类型类别相关的以下内容:

类型定义创建一个新的、不同的类型,它具有与给定类型相同的基础类型和操作,并将标识符绑定到它。

所以我的理解是,定义的类型是与给定类型不同的新类型,但它们属于同一类型类别,例如接口类型或结构类型。不过,还没有这样的定义。

【问题讨论】:

  • 您在寻找什么定义,或者具体来说您期望什么?每个规范都在同一个文档中:Interface TypesStruct Types。既然你引用的内容的含义似乎很明显,还需要什么进一步的解释?

标签: go types interface


【解决方案1】:

TLDR;

T 类型的种类interface,如果其基础类型是接口类型。

T 类型的 kindstruct 如果其基础类型是结构类型。


Spec: Struct typesSpec: Interface types 准确指定了结构和接口类型:

StructType    = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl     = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag           = string_lit .

InterfaceType      = "interface" "{" { MethodSpec ";" } "}" .
MethodSpec         = MethodName Signature | InterfaceTypeName .
MethodName         = identifier .
InterfaceTypeName  = TypeName .

例如,这些是结构类型:

struct { A int }
struct {}
struct { _ int }

这些是接口类型:

interface { String() string }
interface {}

我们可能会使用type declaration 来创建一个新类型,例如:

type Point struct { X, Y int }

上面的类型定义创建了一个新的、不同的类型,它具有与给定类型相同的underlying type 和操作,并将标识符绑定到它。 底层类型的定义是递归的:

每个类型T 都有一个基础类型:如果T 是预先声明的布尔、数字或字符串类型之一,或者是类型文字,则相应的基础类型是T本身。否则,T 的基础类型是T 在其type declaration 中引用的类型的基础类型。

当我们谈论任意类型是结构或接口时,我们是在谈论它们的种类

鉴于此,基本上你的问题是这样的:

“任意类型接口或结构的种类是什么时候?”

这个问题的答案不在规范中,但我们可以这样定义它:

如果其基础类型是接口类型,则类型T种类接口

同样:

如果其基础类型是结构类型,则类型T种类struct

例如:

type Point struct { X, Y int }

type PP Point

struct { X, Y int } 的类型是 struct 吗?是的,因为它是一个类型字面量,所以它的底层类型就是它本身,并且根据定义它是一个结构类型。

Point 是一个结构吗?由于Point 的底层类型是它在其类型声明中引用的类型的底层类型,它是一个类型文字(见上文),它是结构类型(它的 kind 是结构)。

PP 是一个结构吗?由于它的底层类型是它在类型声明中引用的类型的底层类型(Point),它的底层类型是一个结构类型字面量,是的,它也是一个结构类型。

我们所说的这种种类reflect.Kind 类型表示。有reflect.Interfacereflect.Struct 常量(reflect.Kind 类型)来表示structinterface 种类。而reflect.Type 类型描述符有一个Type.Kind() 方法来访问这种类型。

这是您可以检查某个值的类型(种类)是否为结构的方法,例如:

func isStruct(i interface{}) bool {
    return reflect.TypeOf(i).Kind() == reflect.Struct
}

测试它(在Go Playground 上试试):

fmt.Println(isStruct(Point{}))    // true
fmt.Println(isStruct(PP{}))       // true
fmt.Println(isStruct(struct{}{})) // true
fmt.Println(isStruct("text"))     // false

检查接口类型有点复杂,因为将接口值传递给期望interface{} 的函数不会按原样传递接口值,而是“存储”在其中的具体值,并且作为interface{} 值。我们必须传递一个指向接口的指针(否则这在 Go 中几乎没有意义),访问元素类型并检查它的类型。详情请看这个答案:What is the difference between reflect.ValueOf() and Value.Elem() in go?

【讨论】:

  • 是的,The kind of a type T is interface if its underlying type is an interface type. The kind of a type T is struct if its underlying type is a struct type. 这些词是我在规范中寻找的内容,只是想获得官方定义或声明来说明。但从你的回答中我可以看出没有这样的词,我不是错过了它:)。
【解决方案2】:

接口type 是由interface 关键字引入的类型,或者是由type <em>name</em> interface 定义的此类类型的名称(当然还有该接口的实际要求)。

任何类型,无论是否是接口类型,实现接口类型,如果它具有适当的命名方法集。也就是说,struct 类型可能足以与某些接口类型一起使用。即使是非struct 类型也可能就足够了:

type foo int
func (receiver_arg foo) method1() { ... }

类型名称foo 现在实现任何需要名为method1 的方法的接口(当然前提是它实现了任何所需的其余方法)。

...定义的类型[通过type关键字]是具有给定类型的新的不同类型,但它们属于同一类型类别...

是的,就是这样。使用reflect,您会发现它们具有相同的Kindkind 这个词不在这样的规范中,但它非常有用,这里的链接列举了 Go 中的所有基本类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    • 2011-02-28
    • 2021-11-11
    • 2019-05-10
    相关资源
    最近更新 更多