刘沙河 刘沙河
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希

花开半夏,半夏花开
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希
  • go语言基础

    • 反射
      • 反射定义
        • Python 反射
        • Golang反射
      • 反射的基本用法
        • 获取类型信息
        • 获取类型的值
        • 反射调用函数
      • 结构体反射
        • 1. 获取结构体成员类型
        • 2. 获取结构体成员字段的值
        • 3. 反射执行结构体方法
        • 4. 获取结构体tag的值
      • 反射三定律
        • 1. 接口到反射类型的转换
        • 2. 反射到接口类型的转换
        • 3. 修改反射类型对象
      • 反射的性能
    • nethttp模块
    • Socket编程
    • 内置函数&库
    • Context
    • 正则表达式
    • 环境配置
    • GoPath和GoMod
    • 变量
    • 数据类型
    • 运算符
    • 数据类型相关操作
    • 基础语法
    • 函数&复合类型
    • go指针
    • 函数
    • 数组和切片
    • 结构体
    • 接口
    • 空结构体
    • 文件操作
    • 并发与通道
    • channel 原理和坑
  • go语言进阶

  • go语言实现原理

  • gin框架

  • gorm

  • go测试

  • Go语言
  • go语言基础
bigox
2021-03-22
目录

反射

# 反射定义

# Python 反射

  • python一切皆对象,所以想要通过字符串的形式操作内部成员都可以通过反射去完成操作.

  • py文件 包 类 对象...(导入包操作类调用方法)

  • 反射:根据字符串的形式去某个对象操作对象的成员.

    • getattr(对象名,"方法名")

      • 根据字符串的形式去某个对象中获取对象的成员.

      • attribute属性

      class Foo(object):
          def __init__(self,name):
            self.name = name
          def login(self):
            pass
      obj = Foo('alex')
      
      # 获取变量
      v1 = getattr(obj,'name')
      # 获取方法
      method_name = getattr(obj,'login')
      method_name()
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
    • setattr(对象名称,"变量",值 )

      • 根据字符串的形式去某个对象中设置成员.
      class Foo:
        pass
      obj = Foo()
        obj.k1 = 999
      setattr(obj,'k1',123) # obj.k1 = 123
      
        print(obj.k1)
      
      1
      2
      3
      4
      5
      6
      7
    • hasattr(对象名称,"方法名")

      • 根据字符串的形式去某个对象中判断是否含有某成员.返回布尔类型
        class Foo:
            pass
        
        obj = Foo()
        obj.k1 = 999
        hasattr(obj,'k1')
        print(obj.k1)
      
      1
      2
      3
      4
      5
      6
      7
    • delattr(对象,"方法名")

    • 根据字符串的形式去某个对象中删除某成员.

    class Foo:
        pass
    
    obj = Foo()
    obj.k1 = 999
    delattr(obj,'k1')
    print(obj.k1)
    
    1
    2
    3
    4
    5
    6
    7
  • importlib 用字符串的形式导入模块

    模块 = importlib.import_module('utils.redis')
    
    1
    • 示例:
    import importlib
    
    #用字符串的模式导入模块
    redis = importlib.import_module("utils.redis")
    #用字符串的形式去对象(模块)找到他的成员
    getattr(redis,"func")()
    
    1
    2
    3
    4
    5
    6
    self.MIDDLEWARE_CLASSES = [
                'utils.session.SessionMiddleware',
                'utils.auth.AuthMiddleware',
                'utils.csrf.CrsfMiddleware',
            ]
    for mes in self.MIDDLEWARE_CLASSES:
        module_path,class_name=mes.rsplit('.',maxsplit=1)       #切割路径和类名
        module_object = importlib.import_module(module_path)    #插入模块-字符串操作
        cla=getattr(module_object,class_name)        #根据模块对象找到类名(字符串操作-反射)
        obj = cla()      #实例化对象
    	obj.process()      #运行内部函数process
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

# Golang反射

  • 反射是指程序在运行期间,动态地更新、获取变量的值,包括获取字段类型、名称、调用类变量对应的方法等。

  • 在运行时更新变量和检查他们的值并调用他们的方法和他们支持的内在操作, 但是在编译时b并不知道这些变量的具体类型; 这种机制叫做反射

  • python的反射和Golang反射的区别

    • python反射:
      • 确认对象的类
      • 确认类中所有的成员变量和方法
      • 动态调用任意一个对象的方法
    • golang反射
      • 不支持对字符串解析!
      • 获取对象的值和类型,获取结构体成员的类型, 调用结构体方法
      • 只能作用于已经存在的对象上
  • 变量包括两部分:

    • 类型信息, 这部分是原信息, 是预定义好的
    • 值类型, 这部分在程序运行过程中是动态改变的
  • 反射与空接口

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

    • reflect.TypeOf() 获取变量类型信息, 返回一个type接口
    • reflect.ValueOf() 获取变量值信息
    • reflect.Kind() 获取变量类型
package main
import (
	"fmt"
	"reflect"
)
func main() {
	var x float64 = 3.4
	t := reflect.TypeOf(x)  // t是一个type对象
	fmt.Println(reflect.TypeOf(t))  //*reflect.rtype
	fmt.Println("type:", t.Kind())  // float64
}
1
2
3
4
5
6
7
8
9
10
11

# 反射的基本用法

  • reflect

    • t := reflect.TypeOf() 获取变量类型信息, 返回一个type接口
    • t := reflect.ValueOf() 获取变量值信息
    • t.Kind() 获取变量类型
  • t.Elem() 反射获取指针变量所指向的元素类型

    • t.Name() 获取变量类型名称
  • reflect.Kind() 获取到的变量种类:

    const  (
    	Invalid Kind = iota   // 非法类型
    	Bool
    	Int		//有符号整形
    	Int8   // 有符号8位整形
    	Int16
    	Int32
    	Int64
    	Uint   //无符号整形
    	Uint8	// 无符号8位整形
    	Uint16
    	Uint32
    	Uint64
    	Uintptr   //指针
    	Float32
    	Float64
    	Complex64  //64位复数
    	Complex128  //128位复数
    	Array
    	Chan
    	Func
    	Interface
    	Map
    	Ptr   //指针
    	Slice
    	String
    	Struct
    	UnsafePointer   //底层指针
    )
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

# 获取类型信息

  • reflect.TypeOf() 获取变量类型信息, 返回一个type接口

package main

import (
	"fmt"
	"reflect"
)

type Number int
type Person struct {
}

func checkType(t reflect.Type) {
	if t.Kind() == reflect.Ptr {
		fmt.Printf("变量的类型名称:%v; 指向的变量为:%s\n", t.Kind(), t.Elem())

	}
	fmt.Printf("变量的类型名称=> %v; ;类型种类=>:%s\n", t.Name(), t.Kind())
}

func main() {
	var number Number = 1
	typeOfNumber := reflect.TypeOf(number)
	fmt.Println("type of number:")
	checkType(typeOfNumber)

	var person Person
	typeOfPerson := reflect.TypeOf(person)
	fmt.Println("type of person")
	checkType(typeOfPerson)

	typeOfPersonPtr := reflect.TypeOf(&person)
	fmt.Println("type of &person")
	checkType(typeOfPersonPtr)

}
/**
type of number:
变量的类型名称=> Number; ;类型种类=>:int
type of person
变量的类型名称=> Person; ;类型种类=>:struct
type of &person
变量的类型名称:ptr; 指向的变量为:main.Person
变量的类型名称=> ; ;类型种类=>:ptr
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 获取类型的值

  • t :=reflect.ValueOf() 获取变量值信息
  • 获取变量的值和反射调用函数都需要使用reflect.ValueOf()
  • t.Kind() == reflect.TypeOf()
  • t.SetInt( intnumber ) 改变类型的值,因为是值传递,必须传入指针才能改变值
package main 

import (
	"fmt"
	"reflect"
)

func getVlaue(arg interface{}) {
	argReflectValue := reflect.ValueOf(arg)
	fmt.Printf("arg value : %v\n", argReflectValue)
	fmt.Printf("arg type :%v\n", argReflectValue.Kind())

	switch argReflectValue.Kind() {
	case reflect.Int:
		fmt.Println("arg type is int")
	case reflect.Float32:
		// fmt.Println("arg type is float32")
		res := argReflectValue.Elem()
		res.SetFloat(2.6)
		fmt.Println(res)
	case reflect.Ptr:
		fmt.Println("arg type is pointer")
		res := argReflectValue.Elem()
		res.SetFloat(2.6)     // 改变传入参数的值, 必须传入指针类型才可以改变
		fmt.Println(res)

	default:
		fmt.Println("not fond")

	}
}

func main() {
	var f float32 = 1.3
	getVlaue(&f)

}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 反射调用函数

  • 反射调用函数: 使用reflect.ValueOf() 方法传入想要反射的函数名, 获取到reflect.Value对象, 再通过该对象啊的call方法调用该函数;

  • Call 方法需要提前声明;

    func (v Value) Call (in []Value) []Value
    
    1
    • call 方法输入的参数in调用v持有的函数.
    • 例如, 如果len(in) == 3, v.Call(in) 代表调用v(int[0],int[1],int[2]), 其中value值表示其持有值. 如果v的kind不是func将会panic.. 它返回函数所有输出结果的Value封装的切片。和Go代码一样,每一个输入实参的持有值都必须可以直接赋值给函数对应输入参数的类型。如果v持有值是可变参数函数,Call方法会自行创建一个代表可变参数的切片,将对应可变参数的值都拷贝到里面。
    
    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    func Equal(a, b int) bool {
    	if a == b {
    		return true
    	}
    	return false
    }
    
    func main() {
    	// reflect.Value 类型
    	valueOfFunc := reflect.ValueOf(Equal)
    	// 构造函数参数
    	args := []reflect.Value{reflect.ValueOf(1), reflect.ValueOf(2)}
    
    	// 同各国反射调用函数计算
    	result := valueOfFunc.Call(args)
    
    	fmt.Println("函数运行结果: ", result[0].Bool())  // 函数运行结果:  false
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

# 结构体反射

  • 反射可以获取结构体成员的类型、结构体成员的值、以及调用结构体的方法

# 1. 获取结构体成员类型

  • t := reflect.TypeOf("结构体") // t是reflect.Type类型

    • t.NumField() 获取结构体成员的数量

    • t.Field(index) 可以根据索引返回结构体字段详细信息; 具体信息如下

      type StructField struct{
      	Name string  	//字段名
      	PkgPath string  //字段路径
      	Type Type		//字段反射类型对象
      	Tag StruntTag	//字段结构体标签
      	Offset uinptr	//字段在结构体中的偏移
      	Index  []int 	//字段的索引值
      	Anonymous bool 	//是否为匿名字段
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
    • t.FieldByName(name string) 通过字段名来获取字段信息

    • t.FieldByIndex(index []int) 通过下标来获取字段信息

    // type StructField struct{
    // 	Name string  	//字段名
    // 	PkgPath string  //字段路径
    // 	Type Type		//字段反射类型对象
    // 	Tag StruntTag	//字段结构体标签
    // 	Offset uinptr	//字段在结构体中的偏移
    // 	Index  []int 	//字段的索引值
    // 	Anonymous bool 	//是否为匿名字段
    // }
    
    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type Person struct {
    	Name string
    	Age  int `json:"age"`
    	string
    }
    
    func main() {
    	person := Person{"Evan", 18, "备注"}
    	typeOfPerson := reflect.TypeOf(person)
    	// 遍历结构体成员, 获取字段信息
    	for i := 0; i < typeOfPerson.NumField(); i++ {
    		field := typeOfPerson.Field(i)
    		name := field.Name
    		tag := field.Tag
    		anonymous := field.Anonymous
    		fmt.Printf("字段名:%v 字段标签:%v 是否为匿名字段:%v \n", name, tag, anonymous)
    	}
    	// 通过字段名获取字段信息
    	if field, ok := typeOfPerson.FieldByName("Age"); ok {
    		fmt.Println("通过字段名")
    		fmt.Printf("字段名:%v  字段标签中json为: %v \n", field.Name, field.Tag.Get("json"))
    	}
    
    	// 通过下标获取字段信息
    	field := typeOfPerson.FieldByIndex([]int{1})
    	fmt.Printf("字段名:%v 字段标签: %v \n", field.Name, field.Tag)
    
    }
    /**
    字段名:Name 字段标签: 是否为匿名字段:false
    字段名:Age 字段标签:json:"age" 是否为匿名字段:false
    字段名:string 字段标签: 是否为匿名字段:true
    通过字段名
    字段名:Age  字段标签中json为: age
    字段名:Age 字段标签: json:"age"
    */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53

# 2. 获取结构体成员字段的值

  • t := reflect.Valueof("结构体")

    • t.NumField() 获取结构体成员的数量
    • t.Feild(index) 根据 索引返回的对应结构体字段的reflect.Value 反射类型
    // type StructField struct{
    // 	Name string  	//字段名
    // 	PkgPath string  //字段路径
    // 	Type Type		//字段反射类型对象
    // 	Tag StruntTag	//字段结构体标签
    // 	Offset uinptr	//字段在结构体中的偏移
    // 	Index  []int 	//字段的索引值
    // 	Anonymous bool 	//是否为匿名字段
    // }
    
    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type Person struct {
    	Name string
    	Age  int `json:"age"`
    	string
    }
    
    func main() {
    	person := Person{"Evan", 18, "备注"}
    	valueOfPerson := reflect.ValueOf(person)
    
    	// 结构体字段数量
    	fieldNum := valueOfPerson.NumField()
    	fmt.Printf("结构体字段数量: %d \n", fieldNum) //结构体字段数量: 3
    
    	// 通过下标获取字段值
    	field1 := valueOfPerson.Field(1)
    	fmt.Printf("字段值:%v \n", field1.Int())    //字段值:18
    	field2 := valueOfPerson.Field(0)
    	fmt.Printf("字段值:%v \n", field2.String())  //字段值:Evan
    
    	// 通过字段名获取字段信息
    	field  := valueOfPerson.FieldByName("Age")
    	fmt.Printf("字段值: %v \n", field.Interface())
    
    	//
    	// 通过下标索引获取字段信息
    	field = valueOfPerson.FieldByIndex([]int{1})
    	fmt.Printf("字段值: %v \n", field.Interface())
    
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48

# 3. 反射执行结构体方法

  • 结构体方法需要使用reflect.ValueOf() 获取reflect.Value对象, 然后调用该对象的MethodByName(name) 函数, 找到对应要反射调用的方法, 再通过Call函数进行反射调用

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type Person struct {
    	Name string
    	Age  int `json:"age"`
    	string
    }
    
    func (p Person)GetName(a int)  {
    	fmt.Println(p.Name)  // Evan
    
    	fmt.Println(a)  // 1
    }
    
    func main() {
    	valueOfPerson := reflect.ValueOf(Person{"Evan",18,"备注"})
    	callObj  := valueOfPerson.MethodByName("GetName")
    	callObj.Call([]reflect.Value{reflect.ValueOf(1)})
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

# 4. 获取结构体tag的值

  • package main
    
    import (
    	"fmt"
    	"reflect" // 这里引入reflect模块
    )
    
    type User struct {
    	Name   string `json:"user_name"`
    	Passwd string `json:"user_password"`
    }
    
    func main() {
    	user := &User{"chronos", "pass"}
    	s := reflect.TypeOf(user).Elem() //通过反射获取type定义
    	for i := 0; i < s.NumField(); i++ {
    		fmt.Println(s.Field(i).Tag.Get("json")) //将tag输出出来
    	}
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20

# 反射三定律

# 1. 接口到反射类型的转换

  • 反射类型: relect.Type 和 relect.Value

  • 反射可以将接口类型变量转换为反射类型变量

  • reflect.TypeOf() 函数将换入的interface{}类型的变量进行解析后返回refluect.Type类型

  • reflect.ValueOf() 函数将换入的interface{}类型的变量进行解析后返回reflect.Value类型

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type Person struct {
    	Name string
    	Age  int `json:"age"`
    	string
    }
    
    func main() {
    	person := Person{}
    	reflectType := reflect.TypeOf(person)
    	reflectValue := reflect.ValueOf(person)
    	fmt.Printf("person type:%T\n",person)	//person type:main.Person
    	fmt.Printf("reflectType type:%T\n",reflectType)	//reflectType type:*reflect.rtype
    	fmt.Printf("reflectValue type:%T\n",reflectValue)	//reflectValue type:reflect.Value
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

# 2. 反射到接口类型的转换

  • 反射可以将反射类型转换为接口类型

  • reflect.Value 对象的 interface()方法, 可以将反射类型变量转换为接口变量

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    func main() {
    
    	var num = 1
    	valueOfNum := reflect.ValueOf(num)
    	fmt.Println(valueOfNum.Interface())  // 1
    	fmt.Printf("%T",valueOfNum.Interface())  // int
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

# 3. 修改反射类型对象

  • 想要使用反射修改变量的值, 其值必须是可写的( CanSet ).这个值必须满足两个条件:

    1. 变量可以被寻址(CanAddr)
    2. 变量时可以导出的(结构体字段名首字母大写)
    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type Person struct {
    	Name string
    	age  int `json:"age"`
    	string
    }
    
    func main() {
    	person := Person{"Evan",28,"备注"}
    	fmt.Printf("修改前: %v",person)
    	valueOfPerson := reflect.ValueOf(&person)
    	res := valueOfPerson.Elem()
    	res.Field(0).SetString("Jerry")
    	res.Field(1).SetInt(26)
    	//res.Field(2).SetString("啊啊")  // panic
    	fmt.Printf("修改后: %v",person)
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24

# 反射的性能

  • Golang反射性能极差 , 如果需要考虑性能的地方不推荐使用
#Go#
上次更新: 2023/04/16, 18:35:33
nethttp模块

nethttp模块→

最近更新
01
go与http代理
05-24
02
自制申威架构k8s-reloader
12-06
03
Docker Buildx 教程
12-01
更多文章>
Theme by Vdoing | Copyright © 2020-2024 小刘扎扎 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式