Getting started with Golang - Reflection package

Reflection of methods and types

When reflecting, use the program to check its own structure. Yes meta-programming A form of. Reflection can check types and variables at run time. Unless it is really necessary, it should be avoided or used with care.
Two simple functions in the reflection package:

  • reflect. Typeof (I interface {}): returns the type of the checked object
  • reflect. Valueof (I interface {}): returns the value of the checked object
var x float64 = 3.14  
fmt.Println(reflect.TypeOf(x))  
fmt.Println(reflect.ValueOf(x))

Output results:

float64
3.14

In addition, we can use the kind () method to identify reflect The data type returned by valueof(). If the value type of X is float64, then reflect ValueOf(x). Kind( ) == reflect. Float64.

fmt.Printf("%t",reflect.Float64==v.Kind())

Output results:

true

The Kind() method always returns the underlying type.

type MyInt int  
var myint MyInt = 5
fmt.Println(reflect.TypeOf(myint))  
fmt.Println(reflect.ValueOf(myint).Kind())

Output results:

main.MyInt
int

You can see reflect. Net from the output result Typeof() returns the type used when the variable is declared, while Kind() returns the underlying type of the type used when the variable is declared.

The restored value can be obtained by using the Interface() method

fmt.Printf("%v,%[1]T\n%v,%[2]T",v,v.Interface())  
fmt.Println(v.Interface()==reflect.Float64)

Output results:

3.14,reflect.Value
3.14,float64
false

The Interface() method can set reflect The return Value of the valueof() function is converted from the Value type to the original type. Using Float(), Int(), String(), Bool() and other methods can also achieve the same functions.

fmt.Printf("%v,%[1]T\n",v.Float())

Output results:

3.14,float64

Modify values by reflection

The method of SetFloat() can be used to modify the value. You must be careful when using it. If the variable cannot be set, an error will appear. You can use the canset () method to test whether it can be set. The return value of CanSet() method is False. You can use the Elem() method to make it a settable state. You need to get the pointer before using the Elem method.

var Num float64= 3.15  
Value := reflect.ValueOf(Num)  
if ok := Value.CanSet(); ok {  
	fmt.Println("Value Can Set")  
	Value.SetFloat(4.56)  
}else{  
	fmt.Println("Value Cannot Set, Now Elem it")  
	Value := reflect.ValueOf(&Num)  
	Value = Value.Elem()  
	fmt.Println("The CanSet Is ", Value.CanSet())  
	Value.SetFloat(1.23)  
}  
fmt.Println(Value)

Output results:

Value Cannot Set, Now Elem it
The CanSet Is  true
3.15

Be careful to reuse reflect. Before using the Elem method ValueOf(&Num)

Reflective structure

Sometimes you need to reflect a structure type. The NumField() method returns the number of fields within the structure. Get the value field (I) of each field by index through a for loop. At the same time, we can call the method on the signature structure, and we can use the index to call method (n) Call( nil ).

type ThreeString struct{  
	s1,s2,s3 string  
}  
func (s ThreeString)String() string{  
	return s.s1 + "-" + s.s2 + "-"+s.s3  
}  
var secret interface{}=ThreeString{"Alpha","Bete","Omega"}
func main(){
	Value1 := reflect.ValueOf(secret)  
	Type1 := reflect.TypeOf(secret)  
	fmt.Println(Type1)  
	fmt.Println(Value1.Kind())  
	for i := 0 ; i < Value1.NumField() ; i++ {  
	  fmt.Printf("Field %d : %v\n",i,Value1.Field(i))  
	}  
	fmt.Println(Value1)  
	results := Value1.Method(0).Call(nil)  
	fmt.Println(results)
}

Output results:

main.ThreeString
struct
Field 0 : Alpha
Field 1 : Bete
Field 2 : Omega
Alpha-Bete-Omega
[Alpha-Bete-Omega]

However, if field (n) is used To change a value with the setstring() method, an error occurs:

panic: reflect: reflect.Value.SetString using value obtained using unexported field

Because only the exported fields (initial capitalization) in the structure can be set:

type T struct {  
	A int  
	B string  
}
func main() {
	t := T{23,"skidoo"}  
	s := reflect.ValueOf(&t).Elem()  
	typeOfT := s.Type()  
	for i := 0 ; i < s.NumField() ; i++{  
		f := s.Field(i)	
		fmt.Printf("%d:%s %s = %v \n", i, typeOfT.Field(i).Name , f.Type(),f.Interface())  
	}  
	s.Field(0).SetInt(77)  
	s.Field(1).SetString("Sunset Strip")  
	fmt.Println("t is now :",t)
}

Output results:

0:A int = 23
1:B string = skidoo
t is now : {77 Sunset Strip}

Code download

The above program codes have been uploaded to https://github.com/MrLeea-13155bc/Golang , you can download it directly if necessary

Keywords: Go

Added by jcm93 on Sat, 18 Dec 2021 01:15:37 +0200