我一直在尝试理解 Go 中的接口概念。阅读this https://stackoverflow.com/questions/13511203/why-cant-i-assign-a-struct-to-an-interface and this http://research.swtch.com/interfaces帮了很多忙。
唯一让我不舒服的是语法。看一下这个例子 http://play.golang.org/p/-Q-aypjvo_ below:
package main
import "fmt"
type Interface interface {
String() string
}
type Implementation int
func (v Implementation) String() string {
return fmt.Sprintf("Hello %d", v)
}
func main() {
var i Interface
impl := Implementation(42)
i = impl
fmt.Println(i.String())
}
我的问题是i = impl
。基于接口实例实际上持有对实际数据的指针引用这一事实,我觉得这样做更自然i = &impl
。通常不使用时分配非指针&
将制作数据的完整内存副本,但是当分配给接口时,这似乎回避了这一点,而是只需(在幕后)将指针分配给接口值。我对吗?也就是说,数据为int(42)
不会被复制到内存中吗?
数据为int(42)
will被复制。试试这个代码:
func main() {
var i Interface
impl := Implementation(42)
i = impl
fmt.Println(i.String())
impl = Implementation(91)
fmt.Println(i.String())
}
(游乐场链接 http://play.golang.org/p/jjADB29Uyu)
你会发现第二个i.String()
仍然显示42
。也许 Go 更棘手的方面之一是方法接收者也可以是指针。
func (v *Implementation) String() string {
return fmt.Sprintf("Hello %d", *v)
}
// ...
i = &impl
如果您希望接口保存指向原始值的指针,这就是您想要的impl
。 “在幕后”,接口是一个结构,它要么保存指向某些数据的指针,要么保存数据本身(以及出于我们的目的可以忽略的一些类型元数据)。如果数据大小小于或等于一个机器字,则数据本身将被存储 - 无论它是指针、结构还是其他值。
否则它将是指向某些数据的指针,但这是棘手的部分:如果实现接口的类型是结构体,则指针将指向结构体的副本,而不是分配给接口变量本身的结构。或者至少在语义上用户可以这样认为,优化可能允许在两者分歧之前(例如,直到您调用String
或重新分配impl
).
简而言之:分配给接口在语义上可以被认为是实现该接口的数据的副本。如果这是一个指向类型的指针,它会复制该指针,如果它是一个大结构,它会复制该大结构。在底层使用指针的接口的细节是出于垃圾收集的原因并确保堆栈按可预测的量扩展。就开发人员而言,它们应该被视为所分配的实现类型的特定实例的语义副本。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)