zoukankan      html  css  js  c++  java
  • Go反射编程


    go 语言每个对象都包含两个部分:类型和值。go 语言的反射也会返回类型和值

    reflect.TypeOf 和 reflect.ValueOf

    • reflect.TypeOf 返回类型(reflect.Type)
    • reflect.ValueOf 返回值(reflect.Value)
    • 可以从 reflect.ValueOf(f).Type() 获得类型
    • 通过 kind 的来判断类型
    package reflect_learn
    
    import (
    	"fmt"
    	"reflect"
    	"testing"
    )
    
    // 获取类型和值
    func TestTypeAndValue(t *testing.T) {
    	var f int64 = 10
    	t.Log(reflect.TypeOf(f), reflect.ValueOf(f))
    	t.Log(reflect.ValueOf(f).Type())
    }
    
    // 类型检测
    func CheckType(v interface{}) {
    	t := reflect.TypeOf(v)
    	switch t.Kind() {
    	case reflect.Float32, reflect.Float64:
    		fmt.Println("Float")
    	case reflect.Int, reflect.Int32, reflect.Int64:
    		fmt.Println("Integer")
    	default:
    		fmt.Println("Unknown", t)
    	}
    }
    
    // 类型检测测试
    func TestBasicType(t *testing.T) {
    	var f float64 = 12
    	CheckType(f)
    	CheckType(&f)
    }
    

    反射普遍用途

    通过字符串的方式操作成员和方法

    package reflect_learn
    
    import (
    	"fmt"
    	"reflect"
    	"testing"
    )
    
    type Employee struct {
    	EmployeeID string
    	Name       string `format:"name"`
    	Age        int
    }
    
    func (e *Employee) UpdateAge(newVal int) {
    	e.Age = newVal
    }
    
    type Customer struct {
    	CookieID string
    	Name     string
    	Age      int
    }
    
    func TestInvokeByName(t *testing.T) {
    	e := &Employee{"1", "Mike", 30}
    	// 通过字符串获取成员
    	t.Logf("Name: value(%[1]v), Type(%[1]T)", reflect.ValueOf(*e).FieldByName("Name"))
    	if nameField, ok := reflect.TypeOf(*e).FieldByName("Name"); !ok {
    		t.Error("Failed to get 'Name' field.")
    	} else {
    		t.Log("Tag:format", nameField.Tag.Get("format"))
    	}
        // 通过字符串获取方法并调用
    	// Call 中的参数为 []reflect.Value{}
    	// 需要把 int 转为 reflect.Value 类型: reflect.ValueOf(18)
    	// 再将上一步的结果放入切片 []reflect.Value{} 中
    	reflect.ValueOf(e).MethodByName("UpdateAge").Call([]reflect.Value{reflect.ValueOf(18)})
    	t.Log("Updated Age:", e)
    }
    

    reflect.DeepEqual

    可以用来做 slice 和 map 的比较

    package reflect_learn
    
    import (
    	"fmt"
    	"reflect"
    	"testing"
    )
    
    type Customer struct {
    	CookieID string
    	Name     string
    	Age      int
    }
    
    func TestDeepEqual(t *testing.T) {
    	a := map[int]string{1: "one", 2: "two", 3: "three"}
    	b := map[int]string{1: "one", 2: "two", 4: "three"}
    	//fmt.Println(a == b)
    	fmt.Println(reflect.DeepEqual(a, b))
    
    	s1 := []int{1, 2, 3}
    	s2 := []int{1, 2, 3}
    	s3 := []int{2, 3, 1}
    	t.Log("s1 == s2?", reflect.DeepEqual(s1, s2))
    	t.Log("s1 == s3?", reflect.DeepEqual(s1, s3))
    
    	c1 := Customer{"1", "Mike", 40}
    	c2 := Customer{"1", "Mike", 40}
    	fmt.Println(c1 == c2)
    	fmt.Println(reflect.DeepEqual(c1, c2))
    }
    

    万能程序

    package reflect_learn
    
    import (
    	"errors"
    	"fmt"
    	"reflect"
    	"testing"
    )
    
    type Employee struct {
    	EmployeeID string
    	Name       string `format:"name"`
    	Age        int
    }
    
    type Customer struct {
    	CookieID string
    	Name     string
    	Age      int
    }
    
    func fillBySettings(st interface{}, settings map[string]interface{}) error {
    	// func (v Value) Elem() Value
    	// Elem returns the value that the interface v contains or that the pointer
    	// It panics if v's Kind is not Interface or Ptr.
    	// It returns the zero Value if v is nil.
    	if reflect.TypeOf(st).Kind() != reflect.Ptr {
    		// Elem() 获取指针指向的值
    		if reflect.TypeOf(st).Elem().Kind() != reflect.Struct {
    			return errors.New("the first param should be a pointer to the struct type")
    		}
    	}
    
    	if settings == nil {
    		return errors.New("settings is nil")
    	}
    
    	var (
    		field reflect.StructField
    		ok    bool
    	)
    	for k, v := range settings {
    		if field, ok = reflect.ValueOf(st).Elem().Type().FieldByName(k); !ok {
    			continue
    		}
    		if field.Type == reflect.TypeOf(v) {
    			vstr := reflect.ValueOf(st)
    			vstr = vstr.Elem()
    			vstr.FieldByName(k).Set(reflect.ValueOf(v))
    		}
    	}
    	return nil
    }
    
    func TestFillNameAndAge(t *testing.T) {
    	settings := map[string]interface{}{"Name": "Jake", "Age": 40}
    	e := Employee{}
    	// 传入 *Employee 类型
    	if err := fillBySettings(&e, settings); err != nil {
    		t.Fatal(err)
    	}
    	t.Log(e)
    	c := new(Customer)
    	// 传入 *Customer 类型
    	if err := fillBySettings(c, settings); err != nil {
    		t.Fatal(err)
    	}
    	t.Log(*c)
    }
    
  • 相关阅读:
    LCD时序中设计到的VSPW/VBPD/VFPD/HSPW/HBPD/HFPD总结【转】
    【读书笔记::深入理解linux内核】内存寻址【转】
    解决阿里云无法正常使用samba的问题【转】
    谈谈Linux内核驱动的coding style【转】
    linux下使用indent整理代码(代码格式化)【转】
    gcc编译选项【转】
    DirectFB简介以及移植[一]【转】
    Android Framebuffer介绍及使用【转】
    Windows Live Writer离线博客工具使用教程(适用于博客园、CSDN、51CTO等等博客)【转】
    jenkins 入门教程(上)【转】
  • 原文地址:https://www.cnblogs.com/wuyongqiang/p/12155609.html
Copyright © 2011-2022 走看看