Golang 反射

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

变量的内在机制

  • 变量包含类型信息和值信息
  • 类型信息:是静态的元信息,是预先定义好的
  • 值信息:是程序运行过程中动态改变的

反射的使用

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

空接口与反射

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

import (
	"fmt"
	"reflect"
)

// 反射获取interface类型
func relect_type(i interface{}) {
	// typeOf不能直接比较
	t := reflect.TypeOf(i)
	fmt.Println("类型是: ", t)

	// kind() 可以获取具体类型
	k := t.Kind()
	fmt.Println(k)

	switch k {
	case reflect.Float64:
		fmt.Println("i is float64")
	case reflect.String:
		fmt.Println("i is string")
	}
}

func main() {
	var x float64 = 2.4
	relect_type(x)
}

反射获取 interface 值信息

package main

import (
	"fmt"
	"reflect"
)

// 反射获取interface值信息
func relect_value(i interface{}) {
	v := reflect.ValueOf(i)
	fmt.Println(v)
	k := v.Kind()
	switch k {
	case reflect.Float64:
		fmt.Println("a is: ", v.Float())
	}
}

func main() {
	var x float64 = 3.14
	relect_value(x)
}

反射修改值信息

package main

import (
	"fmt"
	"reflect"
)

// 反射修改值信息
func reflect_set_value(i interface{}) {
	v := reflect.ValueOf(i)
	k := v.Kind()
	switch k {
	case reflect.Float64:
		// 值传递无法在反射中修改
		// 反射修改值
		v.SetFloat(99.81)
		fmt.Println("value is, ", v.Float())
	case reflect.Ptr:
		// Elem()获取地址中的值
		v.Elem().SetFloat(88.91)
		fmt.Println("ptr value is, ", v.Elem().Float())
		// 地址
		fmt.Println(v.Pointer())
	}
}

func main() {
	var x float64 = 3.14
	// 反射值类型, 值传递无法在反射中修改
	//reflect_set_value(x)
	//fmt.Println("main value, ", x)
	// 反射一个指针类型
	reflect_set_value(&x)
	fmt.Println("ptr main value, ", x)
}

结构体反射

查看类型、字段和方法

package main

import (
	"fmt"
	"reflect"
)

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

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

func reflect_struct(i interface{}) {
	t := reflect.TypeOf(i)
	fmt.Println("类型: ", t)
	fmt.Println("字符串类型: ", t.Name())

	// 获取值
	v := reflect.ValueOf(i)
	fmt.Println("值: ", v)
	// 获取结构体所有属性
	// 获取结构体字段个数: t.NumField()
	for i := 0; i < t.NumField(); i++ {
		// 取每个字段
		// 通过interface{} 的 TypeOf()获取
		f := t.Field(i)
		// f.Name 字段名称  f.Type  字段类型
		fmt.Printf("%s : %v\t", f.Name, f.Type)

		// 获取字段值信息
		// 通过interface{} 的 ValueOf()获取
		// interface() 获取字段对应的值
		val := v.Field(i).Interface()
		fmt.Println("val: ", val)
	}

	// 获取方法
	// NumMethod(), 获取方法个数
	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}
	reflect_struct(u)
}

查看匿名字段

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)
	// 匿名
	fmt.Printf("%#v\n", t.Field(0))
	// 值信息
	fmt.Println("%#\n", reflect.ValueOf(m).Field(0))
}

修改结构体值

package main

import (
	"fmt"
	"reflect"
)

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

// 修改结构体值
func SetValue(i interface{}) {
	v := reflect.ValueOf(i)
	// 指针类型重新赋值
	v = v.Elem()
	// 取字段
	f := v.FieldByName("Name")
	if f.Kind() == reflect.String {
		f.SetString("lisi")
	}
}

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

调用方法

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, "zs", 20}
	v := reflect.ValueOf(u)
	// 获取方法
	m := v.MethodByName("Hello")
	// 构建参数
	args := []reflect.Value{reflect.ValueOf("wangwu")}
	m.Call(args)
}

获取字段 tag

package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Name string `json:"name01" db:"name02"`
}

func main() {
	var s Student
	v := reflect.ValueOf(&s)
	// 类型
	t := v.Type()
	// 获取字段
	f := t.Elem().Field(0)
	// 获取tag
	fmt.Println(f.Tag.Get("json"))
	fmt.Println(f.Tag.Get("db"))
}
posted @ 2020-03-17 13:10  ZhiChao&  阅读(420)  评论(0编辑  收藏  举报