要点

  • 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\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.应用场景

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

  • 1.序列化和反序列化,比如json, protobuf等各种数据协议
  • 2.各种数据库的ORM, 比如gorm, sqlx等数据库中间件
  • 3.配置文件解析相关的库,比如ymal ini等。