指向界面的指针是否有意义?

时间:2014-01-01 04:30:35

标签: go

此代码无法编译 - 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的记录的指针,但为什么不允许这样做?

1 个答案:

答案 0 :(得分:2)

  

就我而言,I应该是指向实现IF的记录的指针,   但为什么不允许呢?

如果这是你的目标,那你就错了。接口是一个包装器,是一个保证行为的契约。如果您的接口要求方法改变实现类型,则实现类型应该是指针。指向接口本身的指针不会突然使实现类型变为可变。

这样想,如果我有这样的结构:

type A struct {
    b MyType
}

type A2 struct {
    b *MyType
}

mt := MyType{/* initialization stuff */}
a := &A{mt}
a2 := A2{&mt}

然后aa2不等同。如果我想要一个指向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的实现者是裸体类型而不是指向类型的指针,这根本不会改变代码的行为。

现在提出最后一个问题:为什么没有类似于“指向实现此接口的裸类型的指针”的构造?从我的直觉来看,原因是接口是关于行为而不是数据。你用这样的指针做什么?尽管有一个指针,仍然会在裸体类型上调用这些方法,并且由于它们没有被接口暴露,因此您无法访问其任何字段。您也无法写入指向的位置,因为类型可能不匹配。这将是一个无用的结构。

可能可能得到一个等效的断言“这是一个指向实现我的接口的数据的指针吗?”通过使用反射,但在大多数情况下,它可能不是一个非常有趣或有用的东西。