golang 反射中調用方法


反射中調用函數

眾所周知,golang中的函數是可以像普通的int、float等類型變量那樣作為值的,例如:

package main

import "fmt"

func hello() {
  fmt.Println("Hello world!")
}

func main() {
  hl := hello
  hl()
}

prints:

hello world!

既然函數可以像普通的類型變量一樣可以的話,那么在反射機制中就和不同的變量一樣的,在反射中函數和方法的類型(Type)都是reflect.Func,如果要調用函數的話,可以通過Value的Call方法,例如:


func main() {
  hl := hello
  fv := reflect.ValueOf(hl)
  fmt.Println("fv is reflect.Func ?",fv.Kind() == reflect.Func)
  fv.Call(nil)
}

prints:

fv is reflect.Func? true
hello world!

Value的Call方法的參數是一個Value的slice,對應的反射函數類型的參數,返回值也是一個Value的slice,同樣對應反射函數類型的返回值。通過這個例子,相信你一看就明白了:

func prints(i int) string {
  fmt.Println("i =",i)
  return strconv.Itoa(i)
}

func main() {
  fv := reflect.ValueOf(prints)
  params := make([]reflect.Value,1)  //參數
  params[0] := reflect.ValueOf(20)   //參數設置為20
  rs := fv.Call(params)              //rs作為結果接受函數的返回值
  fmt.Println("result:",rs[0].Interface().(string)) //當然也可以直接是rs[0].Interface()
}

prints:

i = 20
result: 20

------------------------------------------------------------------

上面說了在反射中調用函數的例子,接下來我們要談談反射中方法的調用。函數和方法可以說其實本質上是相同的,只不過方法與一個“對象”進行了“綁定”,方法是“對象”的一種行為,這種行為是對於這個“對象”的一系列操作,例如修改“對象”的某個屬性,例如如下:
好了,現在類型和其對應的方法都已經准備好了,那接下來就是如何使用的問題了,我們有了上面調用函數的經驗,只需要再了解一點知識就可以使用了,這一點知識就是MethodMethodByName的API,好了,現在都准備好了,我們就看看如何使用吧。

 

type MyType struct {
i int
name string
}

func (mt *MyType) SetI(i int) {
mt.i = i
}

func (mt *MyType) SetName(name string) {
mt.name = name
}

func (mt *MyType) String() string {
return fmt.Sprintf("%p",mt) + "--name:" + mt.name + " i:" + strconv.Itoa(mt.i)
}



func main() {
myType := &MyType{22,"wowzai"}
//fmt.Println(myType)     //就是檢查一下myType對象內容
//println("---------------")
//mtV := reflect.ValueOf(&myType).Elem()
//fmt.Println("Before:",mtV.MethodByName("String").Call(nil)[0])
//params := make([]reflect.Value,1)
//params[0] = reflect.ValueOf(18)
//mtV.MethodByName("SetI").Call(params)
//params[0] = reflect.ValueOf("reflection test")
//mtV.MethodByName("SetName").Call(params)
//fmt.Println("After:",mtV.MethodByName("String").Call(nil)[0])


mtV := reflect.ValueOf(&myType).Elem()
fmt.Println("Before:",mtV.Method(2).Call(nil)[0])
params := make([]reflect.Value,1)
params[0] = reflect.ValueOf(18)
mtV.Method(0).Call(params)
params[0] = reflect.ValueOf("reflection test")
mtV.Method(1).Call(params)
fmt.Println("After:",mtV.Method(2).Call(nil)[0])

}

  

需要注意的是上面打印的地址是對象在內存的地址,如果你也運行了這段代碼,結果這個地址應該是不同的。

咦,就這樣結束了嗎?當然不是,細心的讀者會發現上面提到的Method好像沒用到啊,恩,是的,聰明的你一看API的介紹我相信你就知道如何將上面的代碼轉換成用Method方法達到同樣的效果:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM