此代码无法编译 - type *IF does not have method MyMethod
:
1 package main
2
3 type IF interface {
4 MyMethod(i int)
5 }
6
7 type AType struct {
8 I *IF
9 }
10
11 func (a *AType) aFunc() {
12 a.I.MyMethod(1)
13 }
但是,如果I
被定义为IF
本身,则编译正常:
1 package main
2
3 type IF interface {
4 MyMethod(i int)
5 }
6
7 type AType struct {
8 I IF // not a pointer
9 }
10
11 func (a *AType) aFunc() {
12 a.I.MyMethod(1)
13 }
就我而言,I
应该是指向实现IF
的记录的指针,但为什么不允许这样做?
答案 0 :(得分:2)
就我而言,
I
应该是指向实现IF
的记录的指针, 但为什么不允许呢?
如果这是你的目标,那你就错了。接口是一个包装器,是一个保证行为的契约。如果您的接口要求方法改变实现类型,则实现类型应该是指针。指向接口本身的指针不会突然使实现类型变为可变。
这样想,如果我有这样的结构:
type A struct {
b MyType
}
type A2 struct {
b *MyType
}
mt := MyType{/* initialization stuff */}
a := &A{mt}
a2 := A2{&mt}
然后a
和a2
不等同。如果我想要一个指向mt的指针,那么我应该使用A2,而不是A.即使我努力尝试并做&a.b
之类的东西,它也永远不会是指向原始mt
的指针。以相同的方式考虑接口,但b是实现接口的类型。当您使用&A{}
时,您尝试使用的内容相当于使用mt
并尝试将其用作指向A2
的指针。
当你有
时func (mt MyType) MyMethod(i int) {
}
然后该接口永远不会包含除mt副本之外的任何内容。如果你想要一个“指向记录的指针”,你必须实现
func (mt *MyType) MyMethod(i int) {
}
这相当于上面A和A2之间的差异,如果你使用第一个实现,你将永远无法获得指向原始对象的指针。
至于为什么,确切地说,你不能在没有显式解除引用的情况下调用指向接口的指针上的方法,尽管Go通常具有透明指针,我不清楚其基本原理。但是,如果您仍然需要指向接口包装器的指针,则在指针实现中调用MyMethod(1)
应该在(*a.I).MyMethod(1)
中工作。请注意,如果IF的实现者是裸体类型而不是指向类型的指针,这根本不会改变代码的行为。
现在提出最后一个问题:为什么没有类似于“指向实现此接口的裸类型的指针”的构造?从我的直觉来看,原因是接口是关于行为而不是数据。你用这样的指针做什么?尽管有一个指针,仍然会在裸体类型上调用这些方法,并且由于它们没有被接口暴露,因此您无法访问其任何字段。您也无法写入指向的位置,因为类型可能不匹配。这将是一个无用的结构。
你可能可能得到一个等效的断言“这是一个指向实现我的接口的数据的指针吗?”通过使用反射,但在大多数情况下,它可能不是一个非常有趣或有用的东西。