Go语言学习笔记-反射和Unsafe

reflect.TypeOf vs reflect.ValueOf

  • reflect.TypeOf 返回类型(reflect.Type)
  • reflect.ValueOf返回值(reflect.Value)
  • 可以从reflect.Value获得类型
  • 通过kind判断类型
package reflect_test

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)

}

func TestDeepEqual(t *testing.T) {
    a := map[int]string{1: "one", 2: "two", 3: "three"}
    b := map[int]string{1: "one", 2: "two", 3: "three"}
    //  t.Log(a == b)
    t.Log("a==b?", 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))
}

type Employee struct {
    EmployeeID string
    Name       string `format:"normal"`
    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"))
    }
    reflect.ValueOf(e).MethodByName("UpdateAge").
        Call([]reflect.Value{reflect.ValueOf(1)})
    t.Log("Updated Age:", e)
}

提高程序的灵活性
降低程序的可读性
降低程序的性能

package flexible_reflect

import (
    "errors"
    "reflect"
    "testing"
)

func TestDeepEqual(t *testing.T) {
    a := map[int]string{1: "one", 2: "two", 3: "three"}
    b := map[int]string{1: "one", 2: "two", 3: "three"}
    //t.Log(a == b)
    t.Log(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))

}

type Employee struct {
    EmployeeID string
    Name       string `format:"normal"`
    Age        int
}

func (e *Employee) UpdateAge(newVal int) {
    e.Age = newVal
}

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 v points to.
    // 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 {
        return errors.New("the first param should be a pointer to the struct type.")
    }
    // 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": "Mike", "Age": 30}
    e := Employee{}
    if err := fillBySettings(&e, settings); err != nil {
        t.Fatal(err)
    }
    t.Log(e)
    c := new(Customer)
    if err := fillBySettings(c, settings); err != nil {
        t.Fatal(err)
    }
    t.Log(*c)
}

你可能感兴趣的:(Go语言学习笔记-反射和Unsafe)