3 回答
TA贡献1886条经验 获得超2个赞
您可以参考文章“ 如何在Go中使用接口 ”(基于“ Russ Cox的接口描述 ”):
什么是界面?
界面是两件事:
这是一套方法,
但它也是一种类型
该
interface{}
类型的空接口是没有方法的接口。由于没有implements关键字,所有类型都实现至少零方法,并且自动完成满足接口,所有类型都满足空接口。
这意味着如果您编写一个将interface{}
值作为参数的函数,则可以为该函数提供任何值。
(这就是Msg
你的问题所代表的:任何价值)
func DoSomething(v interface{}) { // ...}
这是令人困惑的地方:
在
DoSomething
函数内部,什么是v
类型?初学者被认为是“
v
任何类型”,但这是错误的。v
不属于任何类型; 它是interface{}
类型的。将值传递给
DoSomething
函数时,Go运行时将执行类型转换(如果需要),并将值转换为interface{}
值。
所有值在运行时都只有一种类型,而v
一种静态类型是interface{}
。接口值由两个数据字构成:
一个单词用于指向值的基础类型的方法表,
另一个词用于指向该值所持有的实际数据。
附录:这是Russ的文章在界面结构方面相当完整:
type Stringer interface { String() string}
接口值表示为双字对,给出指向存储在接口中的类型的信息的指针和指向相关数据的指针。
将b分配给Stringer类型的接口值会设置接口值的两个字。
接口值中的第一个单词指向我称之为接口表或itable(发音为i-table;在运行时源中,C实现名称为Itab)。
itable从关于所涉及类型的一些元数据开始,然后成为函数指针的列表。
请注意,itable对应于接口类型,而不是动态类型。
就我们的例子而言,Stringer
持有类型Binary 的itable 列出了用于满足Stringer的方法,它只是String
:Binary的其他方法(Get
)没有出现在itable
。接口值中的第二个字指向实际数据,在这种情况下是一个副本
b
。
由于var s Stringer = b
制作副本的原因相同,分配会复制b
而不是指向:如果稍后更改,并且应该具有原始值,而不是新值。 存储在接口中的值可能是任意大的,但只有一个字专用于将值保存在接口结构中,因此赋值在堆上分配一块内存并将指针记录在单字槽中。b
var c uint64 = b
b
s
c
TA贡献1951条经验 获得超3个赞
它被称为空接口,由所有类型实现,这意味着您可以在该Msg字段中放置任何内容。
示例:
body := Body{3}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:3}
body = Body{"anything"}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:"anything"}
body = Body{body}
fmt.Printf("%#v\n", body) // -> main.Body{Msg:main.Body{Msg:"anything"}}
这是一个类型实现接口的事实的逻辑扩展,只要它具有接口的所有方法。
- 3 回答
- 1 关注
- 1372 浏览
添加回答
举报