日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Golang的reflect

發布時間:2023/12/14 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Golang的reflect 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

      • 1. 概述
      • 2. 反射類型對象
      • 3. 反射的值對象
      • 4. 反射修改值
      • 5. 綜合Demo

1. 概述

Go語言提供了一種機制,能夠在運行時更新變量和檢查它們的值、調用它們的方法和它們支持的內在操作,而不需要在編譯時就知道這些變量的具體類型。這種機制被稱為反射。反射也可以讓我們將類型本身作為第一類的值類型處理。

2. 反射類型對象

使用reflect.TypeOf() 函數獲取任意變量的類型對象 reflect.Type

**函數的源碼如下 : **

// TypeOf returns the reflection Type that represents the dynamic type of i. // If i is a nil interface value, TypeOf returns nil. func TypeOf(i interface{}) Type {eface := *(*emptyInterface)(unsafe.Pointer(&i))return toType(eface.typ) }

通過獲取的類型對象就能訪問原變量的類型信息

在類型信息中我們需要知道 類型(Type) 和 種類(Kind)的區別

類型 Type : 通常指的是系統中的原生數據類型和使用type 關鍵字定義的類型,通過類型對象 reflect.Type中的Name() 方法獲取

種類Kind : 指定的對象的根本種類,是更高一層的概括,通過reflect.Type 中的 Kind() 函數獲取

  • Type的值和Kind的值可能相同,也可能不相同
package mainimport ("fmt""reflect" )type char string type dogs struct { }func main() {var c charStr := "golang go.."// 獲取C的類型對象TypeOfC := reflect.TypeOf(c)// Name() 獲取類型// Kind() 獲取種類fmt.Println("Type = ", TypeOfC.Name(), "Kind = ", TypeOfC.Kind()) // Type = char Kind = stringGolden := dogs{}TypeOfGolden := reflect.TypeOf(Golden)fmt.Println("Type = ", TypeOfGolden.Name(), "Kind = ", TypeOfGolden.Kind()) // Type = char Kind = stringTypeOfStr := reflect.TypeOf(Str)fmt.Println("Type = ", TypeOfStr.Name(), "Kind = ", TypeOfStr.Kind()) //Type = string Kind = stringhuntaway := &dogs{} // 指針變量TypeOfHuntaway := reflect.TypeOf(huntaway)// Go語言中所有的指針變量種類都是 `ptr`// 指針變量的類型是此時是空fmt.Println("Type = ", TypeOfHuntaway.Name(), "Kind = ", TypeOfHuntaway.Kind()) // Type = Kind = ptr// 對指針獲取反射對象時,可以通過 reflect.Elem() 方法獲取這個指針指向的元素類TypeOfHuntaway = TypeOfHuntaway.Elem()fmt.Println("Type = ", TypeOfHuntaway.Name(), "Kind = ", TypeOfHuntaway.Kind()) // Type = dogs Kind = struct }

go run main.go

Type = char Kind = string Type = dogs Kind = struct Type = string Kind = string Type = Kind = ptr Type = dogs Kind = struct

當一個變量是結構體實例的時候,怎么通過反射獲取類型信息呢?

通過 reflect 包中reflect.type的 Field() FieldByIndex FieldByName FieldByNameFunc 方法獲取的 StructField 結構體有些什么內容呢?

// A StructField describes a single field in a struct. type StructField struct {// Name is the field name.Name string// PkgPath is the package path that qualifies a lower case (unexported)// field name. It is empty for upper case (exported) field names.// See https://golang.org/ref/spec#Uniqueness_of_identifiersPkgPath stringType Type // field typeTag StructTag // field tag stringOffset uintptr // offset within struct, in bytesIndex []int // index sequence for Type.FieldByIndexAnonymous bool // is an embedded field } package mainimport ("fmt""reflect" )type dogs struct {Name string `json:"name"`Age int8T int `json:"t" id:"99"` } func main(){// 創建實例Hachiko := dogs{Name:"Hachiko",Age:int8(2),T:66}//獲取反射對象實例typeD := reflect.TypeOf(Hachiko)// NumField()函數,返回結構體成員的數量for i:=0;i<typeD.NumField();i++{// 獲取結構體成員的類型// Field()函數 根據索引返回結構體對應field的信息typeOfField := typeD.Field(i)// 輸出成員字段名稱和tag(標簽信息),成員類型fmt.Printf("%s , %v,%s\n",typeOfField.Name,typeOfField.Tag,typeOfField.Type)}// 通過結構體字段名獲取其類型信息// FieldByName()函數,根據字段名返回字段信息if fieldType,ok := typeD.FieldByName("T");ok{fmt.Println(fieldType.Tag.Get("json"),fieldType.Tag.Get("id"))} }

go run main.go

Name , json:"name",string Age , ,int8 T , json:"t" id:"99",int t 99

3. 反射的值對象

反射可以動態的獲取或者設置變量的值
Go語言中使用reflect.Value獲取和設置變量的值

package mainimport ("fmt""reflect" )func main() {var a int = 99fmt.Printf("a ==> %T,%v\n", a, a)// 使用reflect.ValueOf()函數獲取反射值對象valueOfA := reflect.ValueOf(a)// 獲取的反射值對象,再通過值對象的Interface()方法獲取原值var b int = valueOfA.Interface().(int)fmt.Printf("b ==> %T,%v\n", b, b)// 反射對象的Int()方法獲取int64類型值,然后強制轉換成int32位var c int32 = int32(valueOfA.Int())fmt.Printf("c ==> %T,%v\n", c, c) }

go run main.go

a ==> int,99 b ==> int,99 c ==> int32,99 package mainimport ("fmt""reflect" )type demo struct {a intb stringc boolfloat64d [5]int }func (d *demo) dF1() {fmt.Println(d.a) } func (d *demo) dF2() {fmt.Println(d.b) }func main() {t := demo{99, "golang", true, 98.90, [5]int{1, 2, 3, 5, 6}}// 獲取值對象valueOfT := reflect.ValueOf(t)// NumField()是獲取字段數量fmt.Println(valueOfT.NumField()) // 5// 獲取索引為1的字段fieldOf1 := valueOfT.Field(1)// 打印該值對象的類型fmt.Println(fieldOf1.Type()) // string// 通過字段名查找fieldOfd := valueOfT.FieldByName("d")fmt.Println(fieldOfd.Type()) // [5]int }

go run main.go

5 string [5]int

4. 反射修改值

reflect.Value 也提供了修改版值的方法

package mainimport ("fmt""reflect" )func main() {var age int8 = 99// 獲取一個值對象valueOfAge := reflect.ValueOf(&age)// Elem() 對可尋值的元素獲取它的值// Addr() 對可尋址的元素獲取它地址// CanSet() bool 返回元素(值對象)是否能被設置// CanAddr() bool 返回元素(值對象)是否能被尋址valueOfAge = valueOfAge.Elem()valueOfAgeAddr := valueOfAge.Addr()fmt.Println(valueOfAge) // 99fmt.Println(valueOfAgeAddr) // 0xc000054080fmt.Println(valueOfAge.CanSet()) // truefmt.Println(valueOfAge.CanAddr()) // true// SetInt() 使用int64設置值// SetUint() 使用uint64設置值// SetFloat() 使用float64設置值// SetBool() 使用bool設置值// SetBytes() 設置字節數組[]bytes值// SetString 設置字符串值valueOfAge.SetInt(1)fmt.Printf("age type= %T, value= %v",age,age) }

go run main.go

99 0xc000054080 true true age type= int8, value= 15

通過類型創建類型實例

package mainimport ("fmt""reflect" )func main(){var i int = 99// 獲取反射類型對象typeOfI := reflect.TypeOf(i)// 根據反射類型對象創建類型實例newI := reflect.New(typeOfI)// 答應類型和種類fmt.Println(newI.Type(),newI.Kind()) //*int ptr }

5. 綜合Demo

package mainimport ("fmt""log""reflect" )type Person struct {Name string `json:"name"`Age int `json:"age"`Sex string `json:"sex"` } func (p Person) PersonSet(name string,age int,sex string){p.Name = namep.Age = agep.Sex = sexfmt.Println(p) } func (p Person) ShowPerson(){fmt.Println(p) } func reflectOfStruct(a interface{}){// 獲取reflect.Type類型typeObj := reflect.TypeOf(a)// 獲取reflect.Value類型valueObj := reflect.ValueOf(a)// 獲取Kind類別,下面兩種方法都能獲取KindType := typeObj.Kind()//KindValue := valueObj.Kind()//fmt.Println(KindType)//fmt.Println(KindValue)if KindType != reflect.Struct{log.Fatal("Kind is not error")return}// 獲取字段數量fieldsNum := valueObj.NumField()for i:=0;i<fieldsNum;i++{fmt.Printf("field %d %v\n",i,valueObj.Field(i))// 獲取指定的標簽值tagValue := typeObj.Field(i).Tag.Get("json")if tagValue != ""{fmt.Printf("field %d tag = %v\n",i,tagValue)}}// 獲取方法數量MethodNum := valueObj.NumMethod()fmt.Printf("has %d methods\n",MethodNum)// 調用第一個方法valueObj.Method(1).Call(nil)// 對有參數的方法調用var params []reflect.Valueparams = append(params,reflect.ValueOf("lisi"))params = append(params,reflect.ValueOf(88))params = append(params,reflect.ValueOf("man"))// 傳遞參數,調用指定方法名的方法valueObj.MethodByName("PersonSet").Call(params) } func main() {var a Person = Person{Name:"zhangsan",Age:99,}// 調用函數reflectOfStruct(a) }

go run main.go

field 0 zhangsan field 0 tag = name field 1 99 field 1 tag = age field 2 field 2 tag = sex has 2 methods {zhangsan 99 } {lisi 88 man}

總結

以上是生活随笔為你收集整理的Golang的reflect的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。