golang反射

要點

  • 1.變量
  • 2.反射
  • 3.結構體反射
  • 4.反射總結以及應用場景

1、變量介紹

1.變量的內在機制

  • A、類型信息,這部分是元信息,是預約義好的
  • B、值類型,這部分是程序運行過程當中,動態改變的
var arr [10]int
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
type Animal struct {
    Name string
    age int
}
var a Animal

2、反射介紹

1.反射與空接口

  • A、空接口能夠存儲任何類型的變量
  • B、那麼給你一個空接口,怎麼知道里面存儲的是什麼東西?
  • C、在運行時動態獲取一個變量的類型信息和值信息,就叫反射

2.反射介紹

  • A.內置包 reflect
  • B.獲取類型信息: reflect.TypeOf
  • C.獲取值信息: reflect.ValueOf

3.基本數據類型分析

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x float64 = 3.4
    fmt.Println("type:", reflect.TypeOf(x))
}

4.Type.Kind(),獲取變量的類型

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x float64 = 3.4
    t := reflect.TypeOf(x)
    fmt.Println("type:", t.Kind())
}

5.reflect.ValueOf, 獲取變量的值相關信息

var x float64 = 3.4
v := reflect.ValueOf(x)

// 和reflect.TypeOf功能是同樣的
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:",v.Kind() == reflect.Float64)

fmt.Println("value:",v.Float())

6.經過反射設置變量的值

var x float64 = 3.4
v := reflect.ValueOf(x)

fmt.Println("type:", v.Type())
fmt.Println("kind is float64:",v.Kind() == reflect.Float64)
v.SetFloat(6.8)
fmt.Println("value:", v.Float())

panic,程序崩潰了。sql

7.經過反射設置變量的值

var x float64 = 3.4
// 傳地址進去,不傳地址的話,改變的是副本的值
// 因此在reflect包裏直接崩潰了!!!!
v := reflect.ValueOf(&x)

fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)

v.SetFloat(6.8)
fmt.Println("value:",v.Float())

我靠,還報錯.數據庫

8.經過反射設置變量的值

var x float64 = 3.4
// 傳地址進去,不傳地址的話,改變的是副本的值
// 因此在reflect包裏直接崩潰了!!!!

v := reflect.ValueOf(&x)
fmt.Println("type:",v.Type())
fmt.Println("kind is float64:",v.Kind() == reflect.Float64)

// 經過Elem()獲取指針指向的變量,從而完成賦值操做。
// 正常操做是經過*號來解決的,好比
// var *p int = new(int)
// *p = 100
v.Elem().SetFloat(6.8)
fmt.Println("value:",v.Float())

9.經過反射設置變量的值

var x float64 = 3.4
v := reflect.ValueOf(&x)

fmt.Println("type:",v.Type())
fmt.Println("kind is float64:",v.Kind() == reflect.Float64)

v.Elem().SetInt(100)
fmt.Println("value:",v.Float())

// 我靠,又犯賤了。

結構體反射

1.獲取結構體類型相關信息

package main

import (
    "fmt"
    "reflect"
)

type S struct {
    A int
    B string
}

func main() {
    s := S{23, "skidoo"}
    v := reflect.ValueOf(s)
    t := v.Type()
    
    for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        fmt.Printf("%d: %s %s = %v\n",i,t.Field(i).Name, f.Type(), f.Interface())
    }
}

2.獲取結構體類型相關信息

package main

import (
    "fmt"
    "reflect"
)

type S struct {
    A int
    B string
}

func main() {
    s := S{23, "skidoo"}
    v := reflect.ValueOf(s)
    t := v.Type()
    
    for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        fmt.Printf("%d: %s %s = %v\n",i,t.Field(i).Name, f.Type(), f.Interface())
    }
}

3.設置結構相關字段的值

package main

import (
    "fmt"
    "reflect"
)

type S struct {
    A int
    B string
}

func main() {
    s := S{23, "skidoo"}
    v := reflect.ValueOf(&s)
    t := v.Type()
    
    v.Elem().Field(0).SetInt(100)
    for i := 0; i < v.Elem().NumField(); i++ {
        f := v.Elem().Field(i)
        fmt.Printf("%d: %s %s = %v\n",i, t.Elem().Field(i).Name, f.Type(), f.Interface())
    }
}

4.獲取結構體的方法信息

package main
import (
    "fmt"
    "reflect"
)

type S struct {
    A int
    B string
}

func (s *S) Test() {
    fmt.Println("this is a test")
}

func main() {
    s := S{23, "skidoo"}
    v := reflect.ValueOf(&s)
    t := v.Type()
    v.Elem().Field(0).SetInt(100)
    fmt.Println("method num:", v.NumField())
    for i := 0; i < v.NumMethod(); i++ {
        f := t.Method(i)
        fmt.Printf("%d method, name:%v, type:%v\n", i, f.Name, f.Type)
    }
}

5.調用結構體中的方法

package main

import (
    "fmt"
    "reflect"
)

type S struct {
    A int
    B string
}

func (s *S) Test() {
    fmt.Println("this is a test")
}

func (s *S) SetA(a int) {
    s.A = a
}

func main() {
    s := S{23, "skidoo"}
    v := reflect.ValueOf(&s)
    m := v.MethodByName("Test")
    var args1 []reflect.Value
    m.Call(args1)
    setA := v.MethodByName("SetA")
    var args2 []reflect.Value
    args2 = append(args2, reflect.ValueOf(100))
    setA.Call(args2)
    fmt.Printf("s:%#v\n",s)
}

6.獲取結構體中的tag信息

package main

import (
    "fmt"
    "reflect"
)

type S struct {
    F string `species:"gopher" color:"blue" json:"f"`
}

func main() {
    s := S{}
    st := reflect.TypeOf(s)
    field := st.Field(0)
    fmt.Println(field.Tag.Get("color"), field.Tag.Get("species"), field.Tag.Get("json"))
}

7.應用場景

在運行時動態獲取一個變量的類型信息和值信息就叫作反射json

  • 1.序列化和反序列化,好比json, protobuf等各類數據協議
  • 2.各類數據庫的ORM, 好比gorm, sqlx等數據庫中間件
  • 3.配置文件解析相關的庫,好比ymal ini等。
相關文章
相關標籤/搜索