zoukankan      html  css  js  c++  java
  • golang反射

    要点

    • 1.变量
    • 2.反射
    • 3.结构体反射
    • 4.反射总结以及应用场景

    一、变量介绍

    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
    

    二、反射介绍

    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,程序崩溃了。

    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
    ",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
    ",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
    ",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
    ", 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
    ",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.应用场景

    在运行时动态获取一个变量的类型信息和值信息就叫做反射

    • 1.序列化和反序列化,比如json, protobuf等各种数据协议
    • 2.各种数据库的ORM, 比如gorm, sqlx等数据库中间件
    • 3.配置文件解析相关的库,比如ymal ini等。
  • 相关阅读:
    [转]编程能力与编程年龄
    github for windows 使用
    github 改位置
    Linux下设置和查看环境变量
    Docker基础 :网络配置详解
    docker入门实战笔记
    Jenkins +Maven+Tomcat+SVN +Apache项目持续集成构建
    使用nsenter工具进入Docker容器
    Docker从入门到实战(四)
    Docker从入门到实战(三)
  • 原文地址:https://www.cnblogs.com/Csir/p/9896894.html
Copyright © 2011-2022 走看看