Golang的reflect

mac2026-09-26  12

文章目录

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 main import ( "fmt" "reflect" ) type char string type dogs struct { } func main() { var c char Str := "golang go.." // 获取C的类型对象 TypeOfC := reflect.TypeOf(c) // Name() 获取类型 // Kind() 获取种类 fmt.Println("Type = ", TypeOfC.Name(), "Kind = ", TypeOfC.Kind()) // Type = char Kind = string Golden := dogs{} TypeOfGolden := reflect.TypeOf(Golden) fmt.Println("Type = ", TypeOfGolden.Name(), "Kind = ", TypeOfGolden.Kind()) // Type = char Kind = string TypeOfStr := reflect.TypeOf(Str) fmt.Println("Type = ", TypeOfStr.Name(), "Kind = ", TypeOfStr.Kind()) //Type = string Kind = string huntaway := &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_identifiers PkgPath string Type Type // field type Tag StructTag // field tag string Offset uintptr // offset within struct, in bytes Index []int // index sequence for Type.FieldByIndex Anonymous bool // is an embedded field } package main import ( "fmt" "reflect" ) type dogs struct { Name string `json:"name"` Age int8 T 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 main import ( "fmt" "reflect" ) func main() { var a int = 99 fmt.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 main import ( "fmt" "reflect" ) type demo struct { a int b string c bool float64 d [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 main import ( "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) // 99 fmt.Println(valueOfAgeAddr) // 0xc000054080 fmt.Println(valueOfAge.CanSet()) // true fmt.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 main import ( "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 main import ( "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 = name p.Age = age p.Sex = sex fmt.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.Value params = 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}
最新回复(0)