2014-03-13 196 views
3

如何通过反射获取阴影方法?通过反射获取阴影方法

在下面的代码我使用MethodByName获得方法Test()B类型,但我想获得的阴影法从b.ATest()为好,这样我可以叫他们两个。

package main 

import (
    "fmt" 
    "reflect" 
) 

type A struct {} 
type B struct { 
    A 
} 

func (self *A) Test() { 
    fmt.Println("I'm A") 
} 
func (self *B) Test() { 
    fmt.Println("I'm B") 
} 

func main() { 
    b := &B{} 
    b.Test() // This one shadows b.A.Test() 
    b.A.Test() // but its ok to call like this 

    // via reflection 
    val := reflect.ValueOf(b) 
    val.MethodByName("Test").Call([]reflect.Value{}) 
} 

代码可在这里:http://play.golang.org/p/6YPLy2dmMb

回答

2

如果你有一个嵌入式结构和阴影,你总是可以得到现场就好像它是具有相同的名称作为嵌入式结构类型的成员变量,这由你的行bATest()显示。

那么我们该怎么做?使用reflect.Value.FieldByName来获取字段。用你的确切设置它有点疯狂。您不能在指向结构体的指针上使用FieldByName。

package main 

import (
    "fmt" 
    "reflect" 
) 

type A struct{} 
type B struct { 
    A 
} 

func (self *A) Test() { 
    fmt.Println("I'm A") 
} 
func (self *B) Test() { 
    fmt.Println("I'm B") 
} 

func main() { 
    b := &B{} 
    b.Test() 
    b.A.Test() 

    val := reflect.ValueOf(b) 
    subVal := val.Elem().FieldByName("A").Addr() 
    subVal.MethodByName("Test").Call([]reflect.Value{}) 
    val.MethodByName("Test").Call([]reflect.Value{}) 
} 

正如所见,这有点难看。您首先需要拨打Elem以获取值val分,然后获取该字段,然后获取指向该字段的指针,因为A.Test实际上是(*A),而不是A。虽然Go指针通常是透明的,但不幸的是,它不适用于反射,所以你必须自己做所有的显式寻址/解引用,但是如果你理解指针就很简单。

编辑:Playground link to the code above

+0

好的,谢谢!在我真正的问题中,我真的不知道A的名称,但我想我可以遍历所有字段,并调用该方法,如果它存在于该字段。 – fredrik

2

当您嵌入一个结构到另一个,比方说成B,你只能做在结构B中的字段命名为A型A.作为一个语法上的方便,你可以调用一个方法直接在B上,但在语义上没有关于“阴影方法”的特殊事情;它们只是一个类型A值的方法,恰好在结构中。

你只需要模仿你的b.A.Test()与reflecion API。不好的一面是,反射不会执行普通Go的那种糖,所以你需要模仿的东西是(&((*b).A)).Test()

val.Elem(). // Go to *B 
FieldByName("A").  // Find field named A 
Addr().    // Take its address, since Test has a method receiver of type *A 
MethodByName("Test"). // Find its method Test 
Call([]reflect.Value{}) 

更新代码:

http://play.golang.org/p/67xc66ULFz

(顺便说一句,在调用方法接收器的 “自我” 是围棋不地道。)

+0

我意识到我可能滥用了“语法糖”这个词。有一个指针方法接收器“继承”其指向类型的方法集,并嵌入其他结构,确实会产生语义影响。例如,如果您有'Tester interface {Test()}'类型,所有'B {}','&B {}','A {}'和'&A {}'都可以是测试者(即使输入* B没有自己的测试方法)。 –

+0

谢谢!叫他们的惯用方式是什么?我见过'(自* A)',而且我见过'(a * A)'。它是后者吗? – fredrik

+0

@fredrik看看这个文档:https://code.google.com/p/go-wiki/wiki/CodeReviewComments#Receiver_Names –