TLDR;
T 类型的种类是interface,如果其基础类型是接口类型。
T 类型的 kind 是 struct 如果其基础类型是结构类型。
Spec: Struct types 和 Spec: 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.Interface 和reflect.Struct 常量(reflect.Kind 类型)来表示struct 和interface 种类。而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?