国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Golang > 正文

詳解Golang利用反射reflect動(dòng)態(tài)調(diào)用方法

2020-04-01 18:50:52
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

編程語(yǔ)言中反射的概念

在計(jì)算機(jī)科學(xué)領(lǐng)域,反射是指一類(lèi)應(yīng)用,它們能夠自描述和自控制。也就是說(shuō),這類(lèi)應(yīng)用通過(guò)采用某種機(jī)制來(lái)實(shí)現(xiàn)對(duì)自己行為的描述(self-representation)和監(jiān)測(cè)(examination),并能根據(jù)自身行為的狀態(tài)和結(jié)果,調(diào)整或修改應(yīng)用所描述行為的狀態(tài)和相關(guān)的語(yǔ)義。

每種語(yǔ)言的反射模型都不同,并且有些語(yǔ)言根本不支持反射。Golang語(yǔ)言實(shí)現(xiàn)了反射,反射機(jī)制就是在運(yùn)行時(shí)動(dòng)態(tài)的調(diào)用對(duì)象的方法和屬性,官方自帶的reflect包就是反射相關(guān)的,只要包含這個(gè)包就可以使用。

多插一句,Golang的gRPC也是通過(guò)反射實(shí)現(xiàn)的。

Golang的官方包 reflect 實(shí)現(xiàn)了運(yùn)行時(shí)反射(run-time reflection)。運(yùn)用得當(dāng),可謂威力無(wú)窮。今天,我們就來(lái)利用reflect進(jìn)行方法的動(dòng)態(tài)調(diào)用……

基本知識(shí)

首先,反射主要與 golang 的 interface 類(lèi)型相關(guān)。一個(gè) interface 類(lèi)型的變量包含了兩個(gè)指針:一個(gè)指向變量的類(lèi)型,另一個(gè)指向變量的值。最常用的莫過(guò)于這兩個(gè)函數(shù):

func main(){ s := "hello world" fmt.Println(reflect.ValueOf(s))  // hello world fmt.Println(reflect.TypeOf(s))  // string}

其中,

  • reflect.ValueOf() 返回值類(lèi)型:reflect.Value
  • reflect.TypeOf() 返回值類(lèi)型:reflect.Type

創(chuàng)建變量

接下來(lái),我們可以使用 reflect  來(lái)動(dòng)態(tài)的創(chuàng)建變量:

func main(){ var s string t := reflect.TypeOf(s) fmt.Println(t)         // string sptr := reflect.New(t) fmt.Printf("%s/n", sptr)    // %!s(*string=0xc00000e1e0)}

需要留意, reflect.New() 返回的是一個(gè) 指針 :

New returns a Value representing a pointer to a new zero value for the specified type. That is, the returned Value's Type is PtrTo(typ).

這時(shí)候,我們可以使用 reflect.Value.Elem() 來(lái)取得其實(shí)際的值:

sval := sptr.Elem()  // 返回值類(lèi)型:reflect.Value

然后再將其轉(zhuǎn)為 interface 并做 type-assertion :

ss := sval.interface().(string)fmt.Println(ss)    // 空字符串

動(dòng)態(tài)調(diào)用

假設(shè)我們已經(jīng)定義了以下的 struct 并實(shí)現(xiàn)了相關(guān)的方法:

type M struct{}type In struct{}type Out struct{} func (m *M) Example(in In) Out { return Out{}}

然后我們就可以通過(guò)下面這種方式來(lái)進(jìn)行調(diào)用了:

func main() { v := reflect.ValueOf(&M{}) m := v.MethodByName("Example") in := m.Type().In(0) out := m.Type().Out(0) fmt.Println(in, out)     inVal := reflect.New(in).Elem()    // 可以將 inVal 轉(zhuǎn)為interface后進(jìn)行賦值之類(lèi)的操作…… rtn := m.Call([]reflect.Value{inVal}) fmt.Println(rtn[0])}

注冊(cè)方法

我們?cè)俣x一個(gè)保存 M 所有方法的 map struct :

type Handler struct { Func  reflect.Value In   reflect.Type NumIn int Out  reflect.Type NumOut int}

然后我們就可以來(lái)遍歷結(jié)構(gòu)體 M 的所有方法了:

func main() { handlers := make(map[string]*Handler) v := reflect.ValueOf(&M{}) t := reflect.TypeOf(&M{}) for i := 0; i < v.NumMethod(); i++ { name := t.Method(i).Name // 可以根據(jù) i 來(lái)獲取實(shí)例的方法,也可以用 v.MethodByName(name) 獲取  m := v.Method(i) // 這個(gè)例子我們只獲取第一個(gè)輸入?yún)?shù)和第一個(gè)返回參數(shù) in := m.Type().In(0) out := m.Type().Out(0) handlers[name] = &Handler{  Func:  m,  In:   in,  NumIn: m.Type().NumIn(),  Out:  out,  NumOut: m.Type().NumOut(), } }}

Elem()

在學(xué)習(xí) reflect 的過(guò)程中,我們發(fā)現(xiàn) reflect.Value 和 reflect.Type 都提供了 Elem() 方法。

reflect.Value.Elem() 的作用已經(jīng)在前面稍微提到了,主要就是返回一個(gè) interface 或者 pointer 的值:

Elem returns the value that the interface v contains or that the pointer v points to. It panics if v's Kind is not Interface or Ptr. It returns the zero Value if v is nil.

reflect.Type.Elem() 的作用則是返回一個(gè)類(lèi)型(如:Array,Map,Chan等)的元素的類(lèi)型:

Elem returns a type's element type. It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 通化县| 广饶县| 海原县| 江华| 通州市| 英德市| 逊克县| 清镇市| 紫金县| 湘乡市| 桂东县| 霞浦县| 中宁县| 平乐县| 临洮县| 郸城县| 太原市| 剑川县| 邵阳市| 枞阳县| 吉隆县| 永顺县| 登封市| 栾城县| 济宁市| 普定县| 天气| 合作市| 集贤县| 清涧县| 乌兰察布市| 多伦县| 雷波县| 日土县| 梁平县| 利津县| 松桃| 墨江| 江阴市| 贡觉县| 石屏县|