reflect筆記

reflect使用和源碼閱讀的心得筆記。golang

TypeOf使用

package main

import (
    "fmt"
    "reflect"
)

type S struct {
    A float64 `usage:"a"`
    B float64 `usage:"b"`
    c float64 `usage:"c"`
}

func (s *S) Add() float64{
    return s.A + s.B
}

func (s *S) Del()float64{
    return s.A - s.B
}

func main() {
    s := S{1.43,2.15,3.24}
    t := reflect.TypeOf(s)//利用unsafe.Pointer的特性將S類型反射爲emptyInterface類型,emptyInterface中的rtype定義與runtime裏的_type對齊。
    fmt.Println(t)//main.S

    fmt.Println(t.Field(1))//{B  float64 usage:"b" 8 [1] false} 返回struct類型的第i個字段信息,從中能夠獲取到字段名,類型,tag,是否匿名等信息
    fmt.Println(t.FieldByName("c"))//{c main float64 usage:"c" 16 [2] false} true
    fmt.Println(t.Field(1).Name)// B
    fmt.Println(t.Field(1).Type)// float64
    fmt.Println(t.Field(1).Tag.Get("usage"))// b
    fmt.Println(t.Field(1).Anonymous)// false

    ps := reflect.TypeOf(&s)

    if ps.Kind() == reflect.Ptr{
        e := ps.Elem()//用於取類型的element type,好比指針指向的類型,slice、Map、Array、channel裏面成員的類型,非以上類型panic
        fmt.Println(e.Field(0))//{A  float64 usage:"a" 0 [0] false}
    }
    //Slice的例子
    list := make([]S,0)
    list = append(list, s)
    ps2 := reflect.TypeOf(list)
    if ps2.Kind() == reflect.Slice{
        fmt.Println(ps2.Elem().Field(2))//{c main float64 usage:"c" 16 [2] false}
    }
}

VauleOf使用

package main

import (
    "fmt"
    "reflect"
)

type S struct {
    A float64 `usage:"a"`
    B float64 `usage:"b"`
    c float64 `usage:"c"`
}

func (s *S) Add() float64{
    return s.A + s.B
}

func (s *S) Del()float64{
    return s.A - s.B
}

func main() {
    s := S{1.43,2.15,3.24}
    v := reflect.ValueOf(s)//填充生成一個s具體類型對應的Value.此處實現也是使用unsafe.Pointer將S類型轉換成emptyInterface類型的指針
    fmt.Println(v)//{1.43 2.15 3.24}
    fmt.Println(v.Field(1))//2.15 只有值的信息
    //fmt.Println(t.Method(0))//panic:由於方法的receiver類型是*S
    fmt.Println(v.Kind())//struct
    t := v.Type()//reflect.Value轉換爲reflect.Type
    fmt.Println(t.Field(2))//{c main float64 usage:"c" 16 [2] false}
    ps := &s
    pv := reflect.ValueOf(ps)
    fmt.Println(pv.Kind())//Ptr
    fmt.Println(pv.Elem())//{1.43 2.15 3.24} 返回指針ps指向或者interface ps包含的value,ps非這兩種類型panic
    fmt.Println(pv.Elem().Field(1))//2.15
}

設值

package main

import (
    "fmt"
    "reflect"
)

type S struct {
    A float64 `usage:"a"`
    B float64 `usage:"b"`
    C float64 `usage:"c"`
}

func (s *S) Add() float64{
    return s.A + s.B
}

func (s *S) Del()float64{
    return s.A - s.B
}


func main() {
    a := S{1.43,2.15,3.24}
    b := S{1.11,2.22,3.33}
    va := reflect.ValueOf(a)
    vb := reflect.ValueOf(b)
    fmt.Println(va)// {1.43 2.15 3.24}
    fmt.Println(vb)// {1.11 2.22 3.33}
    //va.Field(0).SetFloat(1.11) //panic:using unaddressable value
    //va.Set(vb) //panic:using unaddressable value
    //上面兩種方法不可設置va的值緣由以下:
    fmt.Println(va.CanSet())// false va不可設置,是否可設置是由Value的flag控制
    //由於golang傳參只有值傳遞因此va := reflect.ValueOf(a)實質上是取的a的副本的Value,
    //改變va是沒法改變a的值的,正確作法以下
    pva := reflect.ValueOf(&a)
    pva.Elem().Field(0).SetFloat(1.11)
    fmt.Println(pva.Elem())//{1.11 2.15 3.24}
    pva.Elem().Set(vb)
    fmt.Println(pva.Elem())//{1.11 2.22 3.33}
}
相關文章
相關標籤/搜索