一尘不染

通过嵌入在struct中的接口进行反射-如何检测“真实”函数?

go

我现在遇到的情况与在该线程中询问的情况相同:
具有嵌入式匿名接口的结构的含义?

  type A interface {
     Foo() string
  }

  type B struct {
     A
     bar string
  }

习惯上,来自OOP语言的背景,这种模式对我来说似乎是“试图说”,因为B必须实现接口A。但是现在我知道“
Go是不同的”。因此,无论有没有进行编译,它都比我最初期望的编译时检查要好。

  func (B) Foo() string { .... }

当下。正如上面的问题指出的那样(解释):“在仅希望实现接口的/ part /的情况下,在结构中使用嵌入式接口非常有用”。

据推测,这是因为此嵌入发生的情况与其他所有情况一样-类型B的值将具有类型A的匿名接口值作为字段。就我个人而言,虽然我发现正交性令人欣慰,但同时也使反射包让我以这种方式直接从B的类型中获取A的方法感到困惑,而如果没有使用接收方B的方法,则不会出错/为零。但是-
这个问题不是关于其背后的想法-它是关于在以下情况下如何初始化接口值b := B{}

 func main() {
    bType := reflect.TypeOf(B{})
    bMeth, has := bType.MethodByName("Foo")
    if has {
      fmt.Printf("HAS IT: %s\n",bMeth.Type.Kind())
      res := bMeth.Func.Call([]reflect.Value{reflect.ValueOf(B{})})
      val := res[0].Interface()
      fmt.Println(val)
  } else {
      fmt.Println("DOESNT HAS IT")
  }
}

运行此命令时,会导致严重的恐慌

 HAS IT: func
 panic: runtime error: invalid memory address or nil pointer dereference

或没有 -取决于编译器/运行时是否能够找到上述方法。因此: 在触发该情况之前如何检测到该情况?

那就是-
关于bMeth值,我可以用来查看反射返回的Method和func值中没有“真实”实现吗?更确切地说,是像“指向匿名接口值的函数表中的函数的指针为零”,还是从没有实现的反射的接口中拉出的方法到底发生了什么?

将整个过程包装在goroutine中并尝试在defer / panic下运行该函数不是答案-不仅因为panic /
defer的开销很大,而且因为该函数通常(如果 确实 存在)可能会产生副作用我现在不想要…

我是否需要类似编译器类型检查的运行时实现之类的东西?还是有更简单的方法?我在想这个吗?

上面的示例在Go游乐场


阅读 224

收藏
2020-07-02

共1个答案

一尘不染

你不需要在我心中反思

method_in_table := B.Foo
fmt.Printf("%T \n", method_in_table)

将输出你

func(main.B) string

接口类型A在预先声明的nil初始化,没有动态类型

var a A
if a==nil{
    fmt.Printf("It's nil")
}
a.Foo()

会给你同样的错误。所以实际检查可以

if b.A != nil { b.Foo()}
2020-07-02