go语言 | 图解反射(一)

反射

反射是指在程序运行期对程序本身进行访问和修改的能力

变量的内在机制

变量包含类型信息和值信息 var arr [10]int arr[0] = 10
类型信息:是静态的元信息,是预先定义好的
值信息:是程序运行过程中动态改变的

反射的使用

reflect包封装了反射相关的方法
获取类型信息:reflect.TypeOf,是静态的
获取值信息:reflect.ValueOf,是动态的

示例1

package main

import (
	"fmt"
	"reflect"
)

type User struct {
	Name string
	Age  int
}

func main() {
	u := User{"tom", 27}

	// 获取类型的具体信息
	t := reflect.TypeOf(u)
	fmt.Println(t.Name()) // User
	fmt.Println(t.Kind()) // struct
	v := reflect.ValueOf(u)
	fmt.Println(v)
}

输出:

User
struct
{tom 27}

示例2

反射可以在运行时动态获取程序的各种详细信息
反射获取interface类型信息

package main

import (
	"fmt"
	"reflect"
)

//反射获取interface类型信息

func reflect_type(a interface{}) {
	t := reflect.TypeOf(a)
	fmt.Println("类型是:", t)
	// kind()可以获取具体类型
	k := t.Kind()
	fmt.Println(k)
	switch k {
	case reflect.Float64:
		fmt.Printf("a is float64\n")
	case reflect.String:
		fmt.Println("string")
	}
}

func main() {
	var x float64 = 3.4
	reflect_type(x)
}

输出

类型是: float64
float64
a is float64

示例3

反射获取interface值信息

package main

import (
	"fmt"
	"reflect"
)

//反射获取interface值信息

func reflect_value(a interface{}) {
	v := reflect.ValueOf(a)
	fmt.Println(v)
	k := v.Kind()
	fmt.Println(k)
	switch k {
	case reflect.Float64:
		fmt.Println("a是:", v.Float())
	}
}

func main() {
	var x float64 = 3.4
	reflect_value(x)
}

输出

3.4
float64
a是: 3.4

示例4

反射修改值信息

package main

import (
	"fmt"
	"reflect"
)

// 反射修改值
func reflect_set_value(a interface{}) {
	v := reflect.ValueOf(a)
	k := v.Kind()
	switch k {
	case reflect.Float64:
		// 反射修改值
		v.SetFloat(6.9)
		fmt.Println("a is ", v.Float())
	case reflect.Ptr:
		// Elem()获取地址指向的值
		v.Elem().SetFloat(7.9)
		fmt.Println("case:", v.Elem().Float())
		// 地址
		fmt.Println(v.Pointer())
	}
}

func main() {
	var x float64 = 3.4
	fmt.Println("main:", x)
	// 反射认为下面是指针类型,不是float类型
	reflect_set_value(&x)
	fmt.Println("main:", x)
}

输出

main: 3.4
case: 7.9
1374390181912
main: 7.9

示例5

查看类型、字段和方法

package main

import (
	"fmt"
	"reflect"
)

// 定义结构体
type User struct {
	Id   int
	Name string
	Age  int
}

// 绑方法
func (u User) Hello() {
	fmt.Println("Hello")
}

// 传入interface{}
func Poni(o interface{}) {
	t := reflect.TypeOf(o)
	fmt.Println("类型:", t)
	fmt.Println("字符串类型:", t.Name())
	// 获取值
	v := reflect.ValueOf(o)
	fmt.Println(v)
	// 可以获取所有属性
	// 获取结构体字段个数:t.NumField()
	for i := 0; i < t.NumField(); i++ {
		// 取每个字段
		f := t.Field(i)
		fmt.Printf("%s : %v", f.Name, f.Type)
		// 获取字段的值信息
		// Interface():获取字段对应的值
		val := v.Field(i).Interface()
		fmt.Println("val :", val)
	}
	fmt.Println("=================方法====================")
	for i := 0; i < t.NumMethod(); i++ {
		m := t.Method(i)
		fmt.Println(m.Name)
		fmt.Println(m.Type)
	}

}

func main() {
	u := User{1, "zs", 20}
	Poni(u)
}

输出

类型: main.User
字符串类型: User
{1 zs 20}
Id : intval : 1
Name : stringval : zs
Age : intval : 20
=================方法====================
Hello
func(main.User)

示例6

查看匿名字段

package main

import (
    "fmt"
    "reflect"
)

// 定义结构体
type User struct {
    Id   int
    Name string
    Age  int
}

// 匿名字段
type Boy struct {
    User
    Addr string
}

func main() {
    m := Boy{User{1, "zs", 20}, "bj"}
    t := reflect.TypeOf(m)
    fmt.Println(t)
    // Anonymous:匿名
    fmt.Printf("%#v\n", t.Field(0))
    // 值信息
    fmt.Printf("%#v\n", reflect.ValueOf(m).Field(0))
}

输出

main.Boy
reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x102b8b100), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:true}
main.User{Id:1, Name:"zs", Age:20}

示例7

修改结构体的值

package main

import (
    "fmt"
    "reflect"
)

// 定义结构体
type User struct {
    Id   int
    Name string
    Age  int
}

// 修改结构体值
func SetValue(o interface{}) {
    v := reflect.ValueOf(o)
    // 获取指针指向的元素
    v = v.Elem()
    // 取字段
    f := v.FieldByName("Name")
    if f.Kind() == reflect.String {
        f.SetString("kuteng")
    }
}

func main() {
    u := User{1, "5lmh.com", 20}
    SetValue(&u)
    fmt.Println(u)
}

输出

{1 kuteng 20}

示例8

调用方法

package main

import (
	"fmt"
	"reflect"
)

// 定义结构体
type User struct {
	Id   int
	Name string
	Age  int
}

func (u User) Hello(name string) {
	fmt.Println("Hello:", name)
}

func main() {
	u := User{1, "5lmh.com", 20}
	v := reflect.ValueOf(u)
	// 获取方法
	m := v.MethodByName("Hello")
	// 构建一些参数
	args := []reflect.Value{reflect.ValueOf("6666")}
	// 没参数的情况下:var args2 []reflect.Value
	// 调用方法,需要传入方法的参数
	m.Call(args)
}

输出

Hello: 6666

示例9

获取字段的tag

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name string `json:"name1" db:"name2"`
}

func main() {
    var s Student
    v := reflect.ValueOf(&s)
    // 类型
    t := v.Type()
    // 获取字段
    f := t.Elem().Field(0)
    fmt.Println(f.Tag.Get("json"))
    fmt.Println(f.Tag.Get("db"))
}

输出

name1
name2

参考

https://www.topgoer.com/%E5%B8%B8%E7%94%A8%E6%A0%87%E5%87%86%E5%BA%93/%E5%8F%8D%E5%B0%84.html

你可能感兴趣的:(go语言,golang,开发语言,后端,反射)