go的反射reflect

我们项目中反射一般是在特定场合获取对象的信息, 然后动态调用对象方法 或者修改对象的属性,但是go里面还有指针【地址】一说法, 来看看是怎么用的

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var x float64 = 3.4
	p := reflect.ValueOf(&x) // Note: take the address of x.
	/*为了得到 p 指向的数据,可以调用 Value 类型的 Elem 方法。
	Elem 方法能够对指针进行“解引用”,然后将结果存储到反射 Value 类型对象 v 中*/
	v := p.Elem()
	v.SetFloat(7.1)
	fmt.Println(x)
}

如果是常见的类型 struct又该如何了:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	type T struct {
		A int
		B string `json:"b"`
	}
	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())
	}
	// 通过字段名, 找到字段类型信息
	if bType, ok := typeOfT.FieldByName("B"); ok {
		// 从tag中取出需要的tag
		fmt.Printf("B has tag %s\n", bType.Tag.Get("json"))
	}
	//修改对象数据
	s.Field(0).SetInt(77)
	s.Field(1).SetString("Sunset Strip")
	fmt.Println("t is now", t)
}

运行结果:

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

如果我们修改了程序让 s 由 t(而不是 &t)创建,程序就会在调用 SetInt 和 SetString 的地方失败,因为 t 的字段是不可设置的。

普通方法的调用

package main

import (
	"fmt"
	"reflect"
)

// 普通函数
func add(a, b int) int {
	return a + b
}
func main() {
	// 将函数包装为反射值对象
	funcValue := reflect.ValueOf(add)
	// 构造函数参数, 传入两个整型值
	paramList := []reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20)}
	// 反射调用函数
	retList := funcValue.Call(paramList)
	// 获取第一个返回值, 取整数值
	fmt.Println(retList[0].Int())
}

接口方法:

package main

import (
	"fmt"
	"reflect"
)

type Table interface {
	TableName() string
}

type Cal interface {
	Add(a, b int) int
}

type model struct{}

func (m model) TableName() string {
	return "table_name"
}

func (m model) Add(a, b int) int {
	return a + b
}
func main() {
	var mod model
	getTableName(mod)
}

/*
reflect.New()函数的声明 func New(typ Type) Value
根据传入的tpye,可以获取到对应的value
*/
func getTableName(v interface{}) {
	rt := reflect.TypeOf(v)
	rv := reflect.ValueOf(v)
	if tabler, ok := rv.Interface().(Table); ok {
		fmt.Println(tabler.TableName())
	}
	if cal, ok := rv.Interface().(Cal); ok {
		fmt.Println(cal.Add(10, 20))
	}
	///
	if tabler, ok := reflect.New(rt).Interface().(Table); ok {
		fmt.Println(tabler.TableName())
	}
	if cal, ok := reflect.New(rt).Interface().(Cal); ok {
		fmt.Println(cal.Add(20, 30))
	}
}

对象方法调用:

package main

import (
	"fmt"
	"reflect"
)

type Person struct {
	Name string
	Age  int
	Sex  string
}

//如果Tool小写后面就没办法反射
type Tool struct {
	Cap string
	Key string
}

func (t Tool) Print() {
	fmt.Println("tool:" + t.Cap + t.Key)
}

func (p Person) PrintInfo(t *Tool) {
	t.Cap = "green"
	t.Key = "long"
	fmt.Printf("姓名:%s, 年龄:%s, 性别:%s, 参数tool内容:%s %s\n", p.Name, p.Age, p.Sex, t.Key, t.Cap)
}

func main() {
	p1 := Person{"Rbuy", 20, "男"}
	///调用person的PrintInfo 方法
	rtyp := reflect.TypeOf(p1)
	rcvr := reflect.ValueOf(p1)
	rmethod, ok := rtyp.MethodByName("PrintInfo")
	if ok {
		// 得到第一个此method第1参数的Type,第零个当然就是结构体本身了
		replyType := rmethod.Type.In(1).Elem()
		//实例化返回值的地址  *tool
		replyv := reflect.New(replyType)
		//rcvr 可以理解为对象实例  replyv 理解为返回值
		rmethod.Func.Call([]reflect.Value{rcvr, replyv})

		//调用tool的print
		var t Tool
		rtyp = reflect.TypeOf(t)
		rmethod, ok = rtyp.MethodByName("Print")
		if ok {
			rmethod.Func.Call([]reflect.Value{replyv.Elem()})
		}
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值