你不能这样做,因为接口值不这样做。
接口值做什么——不管接口类型本身;接口类型是否为空并不重要——它们有两个东西:
某个值的具体类型(或无类型);和
该具体类型的值(或无值)。
因此,如果某个变量v或表达式e的类型I是I接口类型,那么您可以使用某种语法检查这两个“字段”中的一个或两个。它们不是struct字段,因此您不能只使用v.type,但您可以这样做:
switch v.(type) {
case int: // the value in v has type int
case *float64: // the value in v has type float64
// etc
}
这意味着让我看.(type)一下类型字段。switch
获取实际值更难,因为 Go 或多或少需要您先检查类型。在您的情况下,您知道i包含 aDog或 a Cat,因此您可以编写:
var name string
switch i.(type) {
case Dog: name = i.(Dog).name
case Cat: name = i.(Cat).name
default: panic("whatever 'i' is, it is not a Dog or Cat")
}
fmt.Println(name)
这很笨拙,有很多方法可以让它不那么笨拙,但这始终是第一步:弄清楚类型是什么。
好吧,有时在第一步之前有一个步骤:弄清楚变量中是否有任何东西。 你这样做:
if i == nil {
...
}
但是请注意,如果i其中有一些类型化的值,并且该类型可以保存 nil 指针,则value部分i可以为 nil,但仍为i == nilfalse。那是因为i 它确实有一个类型。
var i interface{}
var p *int
if i == nil {
fmt.Println("i is initially nil")
}
if p == nil {
fmt.Println("p is nil")
}
i = p
if i != nil {
fmt.Printf("i is now not nil, even though i.(*int) is %v\n", i.(*int))
}
(在Go 操场上试试这个)。
这通常不是正确的使用方式interface
大多数情况下——也有例外——我们甚至不会尝试查看某个接口的类型。相反,我们定义了一个接口,它提供了方法——我们可以调用的函数——来做我们需要做的事情。请参阅Burak Serdar 的答案,其中接口类型有一个getName方法。然后,与其试图找出某人给了我们一些有限的类型中的哪一种,我们只是说:
name := i.getName()
调用底层具体值的getName 方法。如果i持有 a Dog,则调用func (Dog) getName() string,您需要对其进行定义。如果i持有 a Cat,则调用func (Cat) getName() string。如果您决定将一个名为 的类型添加到您的集合中Bird,您可以定义func (Bird) getName() string,依此类推。
(通常,这些方法也会被导出:GetName,而不是getName。)