golang反射

摘要:
动态更改vararr[10]intarr[0]=10arr[1]=20arr[2]=30arr[3]=40typeAnimalstruct{Namestringageint}varaAnimal II。反思简介1。反射和空接口A,空接口可以存储任何类型的变量B,然后给您一个空接口。

要点

  • 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等。

免责声明:文章转载自《golang反射》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇7步学会在Windows下上架iOS APP流程centos安装redis并开启多个redis实例下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ToStringBuilder和ToStringStyle(覆盖每个实体的 toString 方法)

今天系统要打印日志,发现所有实体的toString()方法 都用的是简单的"+",因为每"+" 一个就会 new 一个 String 对象, 这样如果系统内存小的话会暴内存(前提系统实体比较多)。 由于打印的时候包含包名,感觉太长了, 使用ToStringStyle.SHORT_PREFIX_STYLE 截掉包名 importjava.lang.refl...

C#编程规范(个人使用)

< DOCTYPE html PUBLIC -WCDTD XHTML StrictEN httpwwwworgTRxhtmlDTDxhtml-strictdtd> 1.1.1 类名、公开方法名、属性名使用Pascal 大小写形式; 例如:   public class HelloWorld   {   void SayHello(strin...

基于无锁的C#并发队列实现

最近开始学习无锁编程,和传统的基于Lock的算法相比,无锁编程具有其独特的优点,Angel Lucifer的关于无锁编程一文对此有详细的描述。 无锁编程的目标是在不使用Lock的前提下保证并发过程中共享数据的一致性,其主要的实现基础是CAS操作,也就是compare_and_swap,通过处理器提供的指令,可以原子地更新共享数据,并同时监测其他线程的干...

var和let区别简述

   因为习惯用var声明变量,以至于ES6出了let来替代var,我依然继续用var,直到后来慢慢了解let之后,开始尝试使用     不同点:       ①:var属于ES5规范,let属于ES6规范      ②:var有预处理机制,let没有。预处理机制也就是常说的声明提前       声明提前:不管变量被声明在函数什么位置,所有变量声明都会被提...

tf.GradientTape() 使用

import tensorflow as tfw = tf.constant(1.)x = tf.constant(2.)y = x*wwith tf.GradientTape() as tape: tape.watch([w]) y2 = x*wgrad1 = tape.gradient(y,[w])print(grad1)结果为[None...

ansible使用jinja2模板

jinja2基本语法 控制结构 {% %}             jinja2中的for循环用于迭代Python的数据类型,包括列表,元组和字典          2.变量取值 {{ }}             jinja2模板中使用 {{ }} 语法表示一个变量,它是一种特殊的占位符。当利用jinja2进行渲染的时候,它会把这些特殊的占位符进行填充/...