2014-03-13 120 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 –