【问题标题】:Does pointer to interface make sense?指向接口的指针有意义吗?
【发布时间】:2014-01-01 15:55:52
【问题描述】:

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

【问题讨论】:

    标签: go


    【解决方案1】:

    在我的例子中,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 是实现接口的类型。您尝试对 I 执行的操作相当于采用 &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 的实现者是裸类型而不是指向类型的指针,这根本不会改变代码的行为。

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

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

    【讨论】:

      猜你喜欢
      • 2018-02-09
      • 2018-11-06
      • 2014-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多