Go语言头秃之路(七)

更新系列

Go语言头秃之路(零)
Go语言头秃之路(一)
Go语言头秃之路(二)
Go语言头秃之路(三)
Go语言头秃之路(四)
Go语言头秃之路(五)
Go语言头秃之路(六)


  • 反射
    反射可以在运行时动态获取变量的各种信息

    • 应用场景:
    1. 当不知道接口调用哪个函数,根据传入参数在运行时确定调用的具体接口,这时需要对函数或方法反射。
      eg: func bridge(funcPtr interface{}, args …interface{})
      第一个参数funcPtr以接口形式传入函数指针,函数参数args以可变参数的形式传入,bridge函数中可以用反射来动态执行funcPtr函数。
    2. 对结构体序列化时, 如果结构体有指定tag, 也会使用到反射生成对应的字符串。
    • reflect包实现了运行时反射,允许程序操作任意类型的对象。
      常用方法:
      reflect.TypeOf() 返回 reflect.Type类型
      reflect.ValueOf() 返回 reflect.Value类型
      具体使用:
    func test(i interface{}) {
    	// 1. interface{} -> reflect.Value类型
    	rVal := reflect.ValueOf(b)
    
    	// 2. 将reflect.Value类型转回原来变量类型
    	// reflect.Value类型 -> interface{}
    	iVal := rVal.Interface()
    	// interface{} -> 原来的变量类型 (断言)
    	v := iVal.(Person)
    }
    

    反射的转化关系

    • 需要想要修改反射对应变量值,需要reflect.ValueOf()接收地址,然后使用reflat.Value.Elem().Set…方法
    i := 3
    rVal := reflect.ValueOf(&i)
    fmt.Println(rVal.Kind())   // ptr
    // Elem() 相当于取出指针指向地址的值进行修改
    fmt.Println(rVal.Elem().Int())   // 3
    rVal.Elem().SetInt(6)
    fmt.Println(i)  // 6
    
    • 修改struct反射中元素值的方法(需要传struct地址)
    1. 将反射转化为reflect.Value类型(reflect.ValueOf()),接着转为interface(reflect.Value.Interface()),然后通过断言获得原变量,最后进行赋值即可
    2. 使用Elem() + Field() + Set…(xx)方法
      两种方法饭粒:
      func TestStruct2(i interface{}) {
      	//获取reflect.Value 类型
      	val := reflect.ValueOf(i)
      	
      	// 方法1.
      	// inter := val.Interface()
      	// astruct := inter.(*Monster)
      	// astruct.Name = "黄鼠狼"
      
      	// 方法2. 
      	ele := val.Elem()
      	ele.Field(0).SetInt(500)
      	ele.Field(1).SetString("黄鼠狼")
      	// fmt.Printf("%v, type: %T", ele, ele)
      }
      
    • 一些小程序
    1. 反射应用1:定义两个函数test1和test2, 定义一个适配器函数用作统一处理接口
      func TestReflectFunc(t *testing.T)  {
      	call1 := func(v1 int, v2 int) {
      		t.Log(v1, v2)
      	}
      	call2 := func(v1 int, v2 int, s string) {
      		t.Log(v1, v2, s)
      	}
      	var (
      		function reflect.Value
      		inValue []reflect.Value
      		n int
      	)
      	bridge := func(call interface{}, args...interface{}) {
      		n = len(args)
      		inValue = make([]reflect.Value, n)
      		for i := 0; i<n; i++ {
      			inValue[i] = reflect.ValueOf(args[i])
      		}
      		function = reflect.ValueOf(call)
      		function.Call(inValue)
      	}
      }
      
    2. 反射应用2:使用反射操作任意结构体类型
      type user struct {
      	UserId string
      	Name string
      }
      func TestReflectStruct(t *testing.T)  {
      	var (
      		model *user
      		sv reflect.Value
      	)
      	model = &user{}
      	sv = reflect.ValueOf(model)
      	t.Log("reflect.ValueOf", sv.kind().String())
      	sv = sv.Elem()
      	t.Log("reflect.ValueOf.Elem", sv.Kind().string())
      	sv.FieldByName("UserId").SetString("333333")
      	sv.FieldByName("Name").SetString("Fone")
      	t.Log("model", model)
      }
      
    3. 反射应用3:使用反射创建并操作结构体
      func TestReflectStructPtr(t *testing.T) {
      	var (
      		model *user
      		st reflect.Type
      		elem reflect.Value
      	)
      	st = reflect.TypeOf(model) // 获取类型*user
      	t.Log("reflect.TypeOf", st.Kind().string()) // ptr
      	st = st.Elem()  // st 指向的类型
      	t.Log("reflect.TypeOf.Elem", st.Kind().String()) // struct
      	elem = reflect.New(st)  // New返回一个Value类型值,该值持有一个指向类型为typ的新申请的零值的指针
      	t.Log("reflect.New", elem.Kind().string())  // ptr
      	t.Log("reflect.New.Elem", elem.Elem().kind().String())  // struct
      	// model 就是创建的user结构体变量(实例)
      	model = elem.Interface().(*user)  // model是*user, 它的指向和elem是一样的
      	elem = elem.Elem()  // 取得elem指向的值
      	elem.FieldByName("UserId").SetString("007")   // 赋值
      	elem.FieldByName("Name").SetString("Fone")   // 赋值
      	t.Log("model model.Name", model, model.Name)
      
      }
      
    • 一些注意事项
    1. reflect.ValueOf.Method(i int)
      这里的方法排序是按照方法名(ascii码)首字母顺序。
根据原作 https://pan.quark.cn/s/459657bcfd45 的源码改编 Classic-ML-Methods-Algo 引言 建立这个项目,是为了梳理和总结传统机器学习(Machine Learning)方法(methods)或者算法(algo),和各位同仁相互学习交流. 现在的深度学习本质上来自于传统的神经网络模型,很大程度上是传统机器学习的延续,同时也在不少时候需要结合传统方法来实现. 任何机器学习方法基本的流程结构都是通用的;使用的评价方法也基本通用;使用的一些数学知识也是通用的. 本文在梳理传统机器学习方法算法的同时也会顺便补充这些流程,数学上的知识以供参考. 机器学习 机器学习是人工智能(Artificial Intelligence)的一个分支,也是实现人工智能最重要的手段.区别于传统的基于规则(rule-based)的算法,机器学习可以从数据中获取知识,从而实现规定的任务[Ian Goodfellow and Yoshua Bengio and Aaron Courville的Deep Learning].这些知识可以分为四种: 总结(summarization) 预测(prediction) 估计(estimation) 假想验证(hypothesis testing) 机器学习主要关心的是预测[Varian在Big Data : New Tricks for Econometrics],预测的可以是连续性的输出变量,分类,聚类或者物品之间的有趣关联. 机器学习分类 根据数据配置(setting,是否有标签,可以是连续的也可以是离散的)和任务目标,我们可以将机器学习方法分为四种: 无监督(unsupervised) 训练数据没有给定...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值