3 回答
![?](http://img1.sycdn.imooc.com/545862aa0001f8da02200220-100-100.jpg)
TA贡献1880条经验 获得超4个赞
Aninterface{}是方法集,而不是字段集。如果一个类型的方法包含该接口的方法,则该类型实现该接口。由于空接口没有任何方法,所有类型都实现它。
如果你需要访问一个字段,你必须得到原始类型:
name, ok:=i.(Dog).name
如果i是 a ,这将恢复名称Dog。
或者,为和实现一个getName()函数,然后它们都将实现以下接口:DogCat
type NamedType interface {
getName() string
}
然后你可以将你的函数重写为:
func sayHi(i NamedType) {
fmt.Println(i.getName())
}
![?](http://img1.sycdn.imooc.com/545868cd00013bbb02200220-100-100.jpg)
TA贡献1942条经验 获得超3个赞
你不能这样做,因为接口值不这样做。
接口值做什么——不管接口类型本身;接口类型是否为空并不重要——它们有两个东西:
某个值的具体类型(或无类型);和
该具体类型的值(或无值)。
因此,如果某个变量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。)
![?](http://img1.sycdn.imooc.com/54584d9f0001043b02200220-100-100.jpg)
TA贡献1111条经验 获得超0个赞
就像你说的,interface{}是一个空的界面。你怎么能假设“空”的东西name里面有一个字段(fmt.Println(i.name))?你不能。事实上,go 不支持接口中的字段,只支持方法。
你可以做的(当然有很多解决方案)是定义一个接口(我们称之为它Pet),它有一个返回宠物名字的方法:
type Pet interface {
getName() string
}
然后你可以在函数中接收这个接口(它的对象)sayHi并用它来打印宠物的名字:
func sayHi(i Pet) {
fmt.Println(i.getName())
}
现在,为了能够传递Dog或Cat,sayHi()这两个结构都必须实现接口。因此,getName()为它们定义方法:
func (d Dog) getName() string {
return d.name
}
func (c Cat) getName() string {
return c.name
}
就是这样。
- 3 回答
- 0 关注
- 139 浏览
添加回答
举报