SoFunction
Updated on 2025-03-03

Go language obtains the values ​​of various types of variables through reflection

Reflection is the ability of a program to obtain the type and value of a variable during runtime, or to execute a variable method.

1. What is reflection

Reflection is the ability of a program to obtain the type and value of a variable during runtime, or to execute a variable method.

There are two pairs of very important functions and types in the Golang reflection package, the two functions are:

Able to obtain type information;

A runtime representation that can obtain data;

2、

Golang is a statically typing language, and reflection is based on types.

The type information of any value can be obtained through the () function.

2.1 Type Type and Kind

Types such as int32, slice, map and type keywords customized

Kind can be understood as a specific classification of types. For example, int32 and type MyInt32 are two different types, but they both belong to the int32 type.

Use () to get the variable type and type.

package main
import (
	"fmt"
	"reflect"
)
func main() {
	type MyInt32 int32
	a := MyInt32(1)
	b := int32(1)
	// (a):main.MyInt32 Kind:int32
	("(a):%v Kind:%v\n", (a), (a).Kind())
	// (b):int32 Kind:int32
	("(b):%v Kind:%v\n", (b), (b).Kind())
}

From the code output, we can see that int32 and type MyInt32 are two different types, but they both belong to the int32 type.

Type definitions Click to view:

// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
type Kind uint
const (
	Invalid Kind = iota
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	Array
	Chan
	Func
	Interface
	Map
	Pointer
	Slice
	String
	Struct
	UnsafePointer
)

2.2 Reference to the type pointing to the element

// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Pointer, or Slice.
Elem() Type

In some cases, we need to get the type of the pointer pointing to the element, or the type of the slice element, which can be obtained by the () function.

package main
import (
	"fmt"
	"reflect"
)
type myStruct struct {
}
func main() {
	a := &myStruct{}
	typeA := (a)
	// TypeOf(a):* Kind:ptr
	("TypeOf(a):%v Kind:%v\n", typeA, ())
	// TypeOf(a).Elem(): Elem().Kind:struct
	("TypeOf(a).Elem():%v Elem().Kind:%v\n", (), ().Kind())
	s := []int64{}
	typeS := (s)
	// TypeOf(s):[]int64 Kind:slice
	("TypeOf(s):%v Kind:%v\n", typeS, ())
	// TypeOf(s).Elem():int64 Elem().Kind:int64
	("TypeOf(s).Elem():%v Elem().Kind:%v\n", (), ().Kind())
}

From the code output, we can see that the type of reference pointing to the data can be obtained through the () function.

2.3 Structure member types

Get the number of members through NumField, and Field accesses the member type information StructField through subscripts, including member name, type, Tag information, etc.

package main
import (
	"fmt"
	"reflect"
)
type secStruct struct {
	Cnt []int64
}
type myStruct struct {
	Num   int    `json:"num_json" orm:"column:num_orm"`
	Desc  string `json:"desc_json" orm:"column:desc_orm"`
	Child secStruct
}
func main() {
	s := myStruct{}
	typeS := (s)
	// Number of members	// NumField:3
	("NumField:%v \n", ())
	// Information of each member includes name, type, and tag	for i := 0; i < (); i++ {
		// Access members through subscript		// Field(0):{Name:Num PkgPath: Type:int Tag:json:"num_json" orm:"column:num_orm" Offset:0 Index:[0] Anonymous:false}
		// Field(1):{Name:Desc PkgPath: Type:string Tag:json:"desc_json" orm:"column:desc_orm" Offset:8 Index:[1] Anonymous:false}
		// Field(2):{Name:Child PkgPath: Type: Tag: Offset:24 Index:[2] Anonymous:false}
		("Field(%v):%+v\n", i, (i))
	}
	// Access members by name	field, ok := ("Num")
	// FieldByName("Num") ok:true field:{Name:Num PkgPath: Type:int Tag:json:"num_json" orm:"column:num_orm" Offset:0 Index:[0] Anonymous:false}
	("FieldByName(\"Num\") ok:%v field:%+v\n", ok, field)
	// Get tag value	// json tag val:num_json
	("json tag val:%+v\n", ("json"))
	if value, ok := ("orm"); ok {
		// rm tag val:column:num_orm
		("orm tag val:%+v\n", value)
	}
	// Get the fields of nested structure	// Cnt field:{Name:Child PkgPath: Type: Tag: Offset:24 Index:[2] Anonymous:false}
	("Cnt field:%+v\n", ([]int{2}))
	// Cnt field:{Name:Cnt PkgPath: Type:[]int64 Tag: Offset:0 Index:[0] Anonymous:false}
	("Cnt field:%+v\n", ([]int{2, 0}))
}

3、

By obtaining the variable value and value type, the types are Array, Chan, Map, Slice or String, the length can be obtained through Len().

package main
import (
	"fmt"
	"reflect"
)
func main() {
	b := int32(1)
	valueB := (b)
	// (b):1 Kind:int32
	("(b):%v Kind:%v\n", valueB, ())
	s := "abcdefg"
	valueS := (s)
	// (s):abcdefg Kind:string Len:7
	("(s):%v Kind:%v Len:%v\n", valueS, (), ())
}

3.1 The value of the member of the structure

Similar to 2.3 structure member type obtaining the structure member type, reflect provides NumField to obtain the number of members, and Field accesses the member value through the subscript.

package main
import (
	"fmt"
	"reflect"
)
type secStruct struct {
	Cnt []int64
}
type myStruct struct {
	Num   int    `json:"num_json" orm:"column:num_orm"`
	Desc  string `json:"desc_json" orm:"column:desc_orm"`
	Child secStruct
}
func main() {
	s := myStruct{
		Num:   100,
		Desc:  "desc",
		Child: secStruct{[]int64{1, 2, 3}},
	}
	valueS := (s)
	// Number of members	// NumField:3
	("NumField:%v \n", ())
	// Value of each member	for i := 0; i < (); i++ {
		// Access members through subscript		// value(0):100
		// value(1):desc
		// value(2):{Cnt:[1 2 3]}
		("value(%v):%+v\n", i, (i))
	}
	// Access members by name	value := ("Num")
	// FieldByName("Num") value:100
	("FieldByName(\"Num\") value:%v\n", value)
	// Get the fields of nested structure	// Cnt field:[1 2 3]
	("Cnt field:%+v\n", ([]int{2, 0}))
}

3.2 Traversing array and slice

The values ​​of each element of Array, Slice, or String can be accessed through the subscript through func (v Value) Index(i int) Value.

package main
import (
	"fmt"
	"reflect"
)
func main() {
	s := []int64{1, 2, 3, 4, 5, 6}
	valueS := (s)
	// ValueOf(s):[1 2 3 4 5 6] Kind:slice Len:6
	("ValueOf(s):%v Kind:%v Len:%v\n", valueS, (), ())
	for i := 0; i < (); i++ {
		// (0):1
		// (1):2
		// (2):3
		// (3):4
		// (4):5
		// (5):6
		("(%v):%v\n", i, (i))
	}
}

3.3 traversing map

reflect There are two ways to traverse map

  • Iterate through maps via iterator MapIter
  • First get all keys of the map, and then get the corresponding value through the key
package main
import (
	"fmt"
	"reflect"
)
func main() {
	m := map[int]string{
		1: "1",
		2: "2",
		3: "3",
	}
	valueM := (m)
	// Iterator access	iter := ()
	for () {
		// key:1 val:1
		// key:2 val:2
		// key:3 val:3
		("key:%v val:%v\n", (), ())
	}
	// ------
	("------")
	// Access via key	keys := ()
	for i := 0; i &lt; len(keys); i++ {
		// key:1 val:1
		// key:2 val:2
		// key:3 val:3
		("key:%v val:%v\n", keys[i], (keys[i]))
	}
}

4. Three laws of reflection

Two basic function definitions of reflection:

  • Get type func TypeOf(i any) Type
  • Get the value func ValueOf(i any) Value

where any is an alias for interface{}.

interface{} is an empty interface that does not contain any method signature, and any type implements an empty interface.

Therefore, interface{} can carry (value, concrete type) information of any variable.

4.1 From interface to reflection object

interface{} bears the (value, concrete type) information of the variable, and accesses the value and type of interface{} through the reflection exposure method.

It can be simply understood as the value and information of interface{} is passed to and for easy access.

4.2 From reflection object to interface

The reflected object can be converted to interface{} through the function func (v Value) Interface() (i any) , which is a reverse operation of func ValueOf(i any) Value.

package main
import (
	"fmt"
	"reflect"
)
func main() {
	a := int32(10)
	valueA := (a)
	// ValueOf(a):10
	("ValueOf(a):%v\n", valueA)
	// Interface():10
	("Interface():%v\n", ())
	ai, ok := ().(int32)
	// ok:true val:10
	("ok:%v val:%v\n", ok, ai)
}

4.3 Modify an object by reflection, the object value must be modifiable

reflect provides func (v Value) CanSet() bool to determine whether the object value is modified and modify the object value through func (v Value) Set(x Value).

package main
import (
	"fmt"
	"reflect"
)
func main() {
	a := int32(10)
	valueA := (a)
	// valueA :false
	("valueA :%v\n", ())
	b := int32(100)
	valuePtrB := (&b)
	// valuePtrB:false Elem:true
	("valuePtrB:%v Elem:%v\n", (), ().CanSet())
	().Set((int32(200)))
	// b:200 Elem:200
	("b:%v Elem:%v\n", b, ())
}

This is the article about Go's implementation of obtaining the values ​​of various types of variables through reflection. For more relevant content on obtaining variable values ​​from Go's reflection, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!