欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          詳解Golang的反射(實(shí)例)

          下面由golang教程欄目給大家介紹詳解Golang的反射(實(shí)例),希望對需要的朋友有所幫助!

          詳解Golang的反射(實(shí)例)

          前言

          反射在很多語言中都有其妙用。在計(jì)算機(jī)科學(xué)領(lǐng)域,反射是指一類應(yīng)用,它們能夠***自描述***和***自控制***。

          本文將記錄筆者對于Golang的反射的筆記。

          10s后,以下知識點(diǎn)即將靠近:
          1.反射的簡介
          2.為什么使用反射?
          3.反射具體能做什么

          正文

          1.反射的簡介

          Golang提供了一種機(jī)制,在編譯時(shí)不知道類型的情況下,可更新變量、運(yùn)行時(shí)查看值、調(diào)用方法以及直接對他們的布局進(jìn)行操作的機(jī)制,稱為反射。

          2.為什么使用反射?

          打個(gè)比方,有時(shí)候我們需要一個(gè)函數(shù)可以處理各種類型的值。在不知道類型的情況下,你可能會這么寫:

          // 偽代碼 switch value := value.(type) { case string: 	// ...一些操作 case int:	 	// ...一些操作	 case cbsStruct: // 自定義的結(jié)構(gòu)體	 	// ...一些操作  // ... }

          有沒發(fā)現(xiàn)什么問題?
          這邊存在一個(gè)問題:類型很多,這個(gè)函數(shù)會寫的非常長,而且還可能存在自定的類型,也就是說這個(gè)判斷日后可能還要一直改,因?yàn)闊o法知道未知值到底屬于什么類型。

          無法透視一個(gè)未知類型的時(shí)候,以上代碼其實(shí)不是很合理,這時(shí)候就需要有反射來幫忙你處理,反射使用TypeOf和ValueOf函數(shù)從接口中獲取目標(biāo)對象的信息,輕松完成目的

          3.反射具體能做什么?

          1.獲取變量內(nèi)部信息

          reflect提供了兩種類型來進(jìn)行訪問接口變量的內(nèi)容:

          類型 作用
          reflect.ValueOf() 獲取輸入?yún)?shù)接口中的數(shù)據(jù)的值,如果為空則返回0 <- 注意是0
          reflect.TypeOf() 動態(tài)獲取輸入?yún)?shù)接口中的值的類型,如果為空則返回nil <- 注意是nil

          上代碼

          package main  import ( 	"fmt" 	"reflect" )  func main() { 	var name string = "咖啡色的羊駝"  	// TypeOf會返回目標(biāo)數(shù)據(jù)的類型,比如int/float/struct/指針等 	reflectType := reflect.TypeOf(name)  	// valueOf返回目標(biāo)數(shù)據(jù)的的值,比如上文的"咖啡色的羊駝" 	reflectValue := reflect.ValueOf(name)  	fmt.Println("type: ", reflectType) 	fmt.Println("value: ", reflectValue) }

          輸出:

          type:  string value:  咖啡色的羊駝

          更深一層:在以上操作發(fā)生的時(shí)候,反射將“接口類型的變量”轉(zhuǎn)為了“反射的接口類型的變量”,比如上文實(shí)際上返回的是reflect.Value和reflect.Type的接口對象。(可以根據(jù)ide跟蹤一下相關(guān)函數(shù)返回類型便知)

          2.struct的反射

          package main  import ( 	"fmt" 	"reflect" )  type Student struct { 	Id   int 	Name string }  func (s Student) Hello(){ 	fmt.Println("我是一個(gè)學(xué)生") }  func main() { 	s := Student{Id: 1, Name: "咖啡色的羊駝"}  	// 獲取目標(biāo)對象 	t := reflect.TypeOf(s) 	// .Name()可以獲取去這個(gè)類型的名稱 	fmt.Println("這個(gè)類型的名稱是:", t.Name())  	// 獲取目標(biāo)對象的值類型 	v := reflect.ValueOf(s) 	// .NumField()來獲取其包含的字段的總數(shù) 	for i := 0; i < t.NumField(); i++ { 		// 從0開始獲取Student所包含的key 		key := t.Field(i)  		// 通過interface方法來獲取key所對應(yīng)的值 		value := v.Field(i).Interface()  		fmt.Printf("第%d個(gè)字段是:%s:%v = %v n", i+1, key.Name, key.Type, value) 	}  	// 通過.NumMethod()來獲取Student里頭的方法 	for i:=0;i<t.NumMethod(); i++ { 		m := t.Method(i) 		fmt.Printf("第%d個(gè)方法是:%s:%vn", i+1, m.Name, m.Type) 	} }

          輸出:

          這個(gè)類型的名稱是: Student 第1個(gè)字段是:Id:int = 1  第2個(gè)字段是:Name:string = 咖啡色的羊駝  第1個(gè)方法是:Hello:func(main.Student)

          3.匿名或嵌入字段的反射

          package main  import ( 	"reflect" 	"fmt" )  type Student struct { 	Id   int 	Name string }  type People struct { 	Student // 匿名字段 }  func main() { 	p := People{Student{Id: 1, Name: "咖啡色的羊駝"}}  	t := reflect.TypeOf(p) 	// 這里需要加一個(gè)#號,可以把struct的詳情都給打印出來 	// 會發(fā)現(xiàn)有Anonymous:true,說明是匿名字段 	fmt.Printf("%#vn", t.Field(0))  	// 取出這個(gè)學(xué)生的名字的詳情打印出來 	fmt.Printf("%#vn", t.FieldByIndex([]int{0, 1}))  	// 獲取匿名字段的值的詳情 	v := reflect.ValueOf(p) 	fmt.Printf("%#vn", v.Field(0)) }

          輸出:

          reflect.StructField{Name:"Student", PkgPath:"", Type:(*reflect.rtype)(0x10aade0), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}  reflect.StructField{Name:"Name", PkgPath:"", Type:(*reflect.rtype)(0x109f4e0), Tag:"", Offset:0x8, Index:[]int{1}, Anonymous:false}  main.Student{Id:1, Name:"咖啡色的羊駝"}

          4.判斷傳入的類型是否是我們想要的類型

          package main  import ( 	"reflect" 	"fmt" )  type Student struct { 	Id   int 	Name string }  func main() { 	s := Student{Id: 1, Name: "咖啡色的羊駝"} 	t := reflect.TypeOf(s)  	// 通過.Kind()來判斷對比的值是否是struct類型 	if k := t.Kind(); k == reflect.Struct { 		fmt.Println("bingo") 	}  	num := 1; 	numType := reflect.TypeOf(num) 	if k := numType.Kind(); k == reflect.Int { 		fmt.Println("bingo") 	} }

          輸出:

          bingo bingo

          5.通過反射修改內(nèi)容

          package main  import ( 	"reflect" 	"fmt" )  type Student struct { 	Id   int 	Name string }  func main() { 	s := &Student{Id: 1, Name: "咖啡色的羊駝"}  	v := reflect.ValueOf(s)  	// 修改值必須是指針類型否則不可行 	if v.Kind() != reflect.Ptr { 		fmt.Println("不是指針類型,沒法進(jìn)行修改操作") 		return 	}  	// 獲取指針?biāo)赶虻脑?	v = v.Elem()  	// 獲取目標(biāo)key的Value的封裝 	name := v.FieldByName("Name")  	if name.Kind() == reflect.String { 		name.SetString("小學(xué)生") 	}  	fmt.Printf("%#v n", *s)   	// 如果是整型的話 	test := 888 	testV := reflect.ValueOf(&test) 	testV.Elem().SetInt(666) 	fmt.Println(test) }

          輸出:

          main.Student{Id:1, Name:"小學(xué)生"}  666

          6.通過反射調(diào)用方法

          package main  import ( 	"fmt" 	"reflect" )  type Student struct { 	Id   int 	Name string }  func (s Student) EchoName(name string){ 	fmt.Println("我的名字是:", name) }  func main() { 	s := Student{Id: 1, Name: "咖啡色的羊駝"}  	v := reflect.ValueOf(s)  	// 獲取方法控制權(quán) 	// 官方解釋:返回v的名為name的方法的已綁定(到v的持有值的)狀態(tài)的函數(shù)形式的Value封裝 	mv := v.MethodByName("EchoName") 	// 拼湊參數(shù) 	args := []reflect.Value{reflect.ValueOf("咖啡色的羊駝")}  	// 調(diào)用函數(shù) 	mv.Call(args) }

          輸出:

          我的名字是: 咖啡色的羊駝

          ##4.反射的一些小點(diǎn)

          1.使用反射時(shí)需要先確定要操作的值是否是期望的類型,是否是可以進(jìn)行“賦值”操作的,否則reflect包將會毫不留情的產(chǎn)生一個(gè)panic。

          2.反射主要與Golang的interface類型相關(guān),只有interface類型才有反射一說。如果有興趣可以看一下TypeOf和ValueOf,會發(fā)現(xiàn)其實(shí)傳入?yún)?shù)的時(shí)候已經(jīng)被轉(zhuǎn)為接口類型了。

          // 以下為截取的源代碼 func TypeOf(i interface{}) Type { 	eface := *(*emptyInterface)(unsafe.Pointer(&i)) 	return toType(eface.typ) }  func ValueOf(i interface{}) Value { 	if i == nil { 		return Value{} 	} 	escapes(i)  	return unpackEface(i) }

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號