你不能这样做,因为接口值不这样做。


接口值做什么——不管接口类型本身;接口类型是否为空并不重要——它们有两个东西:


某个值的具体类型(或无类型);和

该具体类型的值(或无值)。

因此,如果某个变量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。)