kaisawind's blog
  • 关于
  • 所有帖子

golang反射的使用 - Fri, Sep 25, 2020

golang反射的使用

1. 概述

golang的反射能够获取对象属性列表,对象函数列表,函数参数列表,并能够给它们尽心赋值和调用。

2. 对象属性列表

使用Field函数时,value必须是对象 NumField()获取属性的个数, Field(i)遍历所有属性

package main

import (
	"context"
	"fmt"
	"reflect"
)

type Struct struct {
	IntField    int
	StringField string
	ArrayField  []string
	MapField    map[string]string
	CtxField    context.Context
	PtrField    *Struct
}

func (s *Struct) Child() *Struct {
	return s.PtrField
}

func main() {
	srt := Struct{
		IntField:    1,
		StringField: "123",
		ArrayField:  []string{"1", "2", "3"},
		MapField:    map[string]string{"1": "1", "2": "2", "3": "3"},
		CtxField:    context.TODO(),
		PtrField:    &Struct{},
	}

	v := reflect.ValueOf(srt)
	fmt.Println(v.Kind())
	num := v.NumField()
	for i := 0; i < num; i++ {
		fmt.Println(v.Field(i).Type(), v.Field(i))
	}
}

output:

struct
int 1
string 123
[]string [1 2 3]
map[string]string map[1:1 2:2 3:3]
context.Context context.TODO
*main.Struct &{0  [] map[] <nil> <nil>}

3. 对象函数列表

指针对象和对象的函数列表不同

func (s *Struct) Child() *Struct {
	return s.PtrField
}

func (s Struct) Child2() *Struct {
	return s.PtrField
}

指针对象的函数列表包含对象的函数列表

// 获取对象函数列表
v := reflect.ValueOf(srt)
num := v.NumMethod()
fmt.Println("struct method", num)
for i := 0; i < num; i++ {
    fmt.Println(v.Type().Method(i).Name, v.Method(i))
}

// 获取指针函数列表
v = reflect.ValueOf(&srt)
num = v.NumMethod()
fmt.Println("ptr method", num)
for i := 0; i < num; i++ {
    fmt.Println(v.Type().Method(i).Name, v.Method(i))
}

output:

struct method 1
Child2 0x4a8780
ptr method 2
Child 0x4a8780
Child2 0x4a8780

4. 函数参数列表

// SetContext static function will not change CtxField
func (s Struct) SetContext(ctx context.Context) {
	s.CtxField = ctx
}
func main() {
	srt := Struct{}

	v := reflect.ValueOf(srt)
	fn := v.MethodByName("SetContext")
	num := fn.Type().NumIn()
	for i := 0; i < num; i++ {
		fmt.Println(fn.Type().In(i).String())
	}
}

output:

context.Context

5. 函数调用

func (s *Struct) SetIntField(val int) {
	s.IntField = val
}
func main() {
	srt := &Struct{}
	v := reflect.ValueOf(srt)
	fn := v.MethodByName("SetIntField")
	fn.Call([]reflect.Value{reflect.ValueOf(10)})

	fmt.Println(srt)
	srt.SetIntField(11)
	fmt.Println(srt)
}

output:

&{10  [] map[] <nil> <nil>}
&{11  [] map[] <nil> <nil>}

6. 函数入参是结构体指针

func (s *Struct) SetPtrField(ptr *Struct) {
	s.PtrField = ptr
}
var val = Struct{
	IntField:    11,
	StringField: "StringField",
	ArrayField:  []string{"1", "2", "3"},
	MapField:    map[string]string{"1": "1", "2": "2"},
}
func main() {
	jsonData, err := json.Marshal(val)
	if err != nil {
		return
	}
	fmt.Println(string(jsonData))
	srt := &Struct{}
	v := reflect.ValueOf(srt)
	fn := v.MethodByName("SetPtrField")
	arg := fn.Type().In(0)
	ptr := reflect.New(arg)     // **Struct
	instance := ptr.Interface() // *Struct
	err = json.Unmarshal(jsonData, instance)
	if err != nil {
		return
	}
	fn.Call([]reflect.Value{ptr.Elem()})

	fmt.Println(srt.PtrField)
}

output:

{"IntField":11,"StringField":"StringField","ArrayField":["1","2","3"],"MapField":{"1":"1","2":"2"},"CtxField":null,"PtrField":null}
&{11 StringField [1 2 3] map[1:1 2:2] <nil> <nil>}

7. 修改函数入参的值

func (s *Struct) SetPtrField(ptr *Struct) {
	s.PtrField = ptr
}
var val = Struct{
	IntField:    11,
	StringField: "StringField",
	ArrayField:  []string{"1", "2", "3"},
	MapField:    map[string]string{"1": "1", "2": "2"},
}
func main() {
	jsonData, err := json.Marshal(val)
	if err != nil {
		return
	}
	fmt.Println(string(jsonData))
	srt := &Struct{}
	v := reflect.ValueOf(srt)
	fn := v.MethodByName("SetPtrField")
	arg := fn.Type().In(0)
	ptr := reflect.New(arg)     // **Struct
	instance := ptr.Interface() // *Struct
	err = json.Unmarshal(jsonData, instance)
	if err != nil {
		return
	}
	ptr = ptr.Elem() // *Struct
	ptr = ptr.Elem() // Struct
	if ptr.CanSet() {
		f := ptr.FieldByName("IntField")
		if f.CanSet() {
			f.Set(reflect.ValueOf(1000))
		}
	}
	fn.Call([]reflect.Value{ptr.Addr()})

	fmt.Println(srt.PtrField)
}

output:

{"IntField":11,"StringField":"StringField","ArrayField":["1","2","3"],"MapField":{"1":"1","2":"2"},"CtxField":null,"PtrField":null}
&{1000 StringField [1 2 3] map[1:1 2:2] <nil> <nil>}

8. 函数返回值

func main() {
	srt := &Struct{
		PtrField: &val,
	}
	v := reflect.ValueOf(srt)
	fn := v.MethodByName("Child")
	values := fn.Call([]reflect.Value{})
	if len(values) == 0 {
		return
	}
	value := values[0]
	ptr := value.Interface().(*Struct)
	fmt.Println(ptr)
}

output:

&{11 StringField [1 2 3] map[1:1 2:2] <nil> <nil>}


辽ICP备2021007608号 | © 2025 | kaisawind

Facebook Twitter GitHub