Type and Value

news2024/9/28 11:18:50

Type and Value

  • 前言
  • 一、reflect.Type
    • 1.1 数据结构
    • 1.2 方法
      • 1.2.1 所有类型通用方法
      • 1.2.2 不同基础类型的专有方法
  • 二、reflect.Value
  • 总结
  • 参考资料

前言

reflect.Type和reflect.Value是go 反射的两大基本类型,一个管变量的类型方面,一个管变量的值方面。

一、reflect.Type

1.1 数据结构

reflect.Type是一个接口,定义了获取变量类型的相关信息的方法,rtype是其实现的结构体,通用的描述公共类型的结构。

type rtype struct {
	size       uintptr
	ptrdata    uintptr // number of bytes in the type that can contain pointers
	hash       uint32  // hash of type; avoids computation in hash tables
	tflag      tflag   // extra type information flags
	align      uint8   // alignment of variable with this type
	fieldAlign uint8   // alignment of struct field with this type
	kind       uint8   // enumeration for C
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B) -> ==?
	equal     func(unsafe.Pointer, unsafe.Pointer) bool
	gcdata    *byte   // garbage collection data
	str       nameOff // string form
	ptrToThis typeOff // type for pointer to this type, may be zero
}

可以通过func TypeOf(i interface{}) Type 来获取一个Type类型的接口变量。

为什么反射接口返回的是一个 Type 接口类型,而不是直接返回 Type ?

  • 因为类型信息是一个只读的信息,不可能动态地修改类型的相关信息,那太不安全了;
  • 因为不同的类型,类型定义也不一样,使用接口这一抽象数据结构能够进行统一的抽象。 所以refelct 包通过 reflect. TypeOf() 函数返回一个 Type 的接口变量,通过接口抽象出来的方法访问具体类型的信息。

1.2 方法

1.2.1 所有类型通用方法

// 所有类型通用的方法
type Type interface {
	// 返回包含包名的类型名字,对于未命名类型返回的是空
	Name() string
	// Kind 返回该类型的底层基础类型
	Kind() Kind
	// 确定当前类型是否实现了 u 接口类型
	// 注意这里的 u 必须是接口类型的 Type
	Implements(u Type) bool
	// 判断当前类型的实例是否能赋位给 type 为 u 的类型交量
	AssignableTo(u Type) bool
	// 判断当前类型的实例是否能强制类型转换为 u 类型交量
	ConvertibleTo(u Type) bool
	// 判断当前类型是否支持比较(等 于或不等于)
	// 支持等于的类型可以作为 map 的 key
	Comparable() bool
	// 返回一个类型的方法的个数
	NumMethod() int
	// 通过索引位访问方法,索引值必须属于[ 0, NumMethod()],否则引发 panic
	Method(int) Method
	// 通过方法名获取 Method
	MethodByName(string) (Method, bool)
	// 返回类型的包路径,如采类型是预声明类型或未命名类型,则返回空字符串
	PkgPath() string
	// 返回存放该类型的实例需要多大的字节空间
	Size() uintptr
}

1.2.2 不同基础类型的专有方法

这些方法是某种类型特有的 , 如果不是某种特定类型却调用了 该类型的方法, 则会引发panic 。所 以为了避免 panic , 在调用特定类型的专有方法前 ,要清楚地知道该类型是什么 ,如果不确定类型,则要先调用 kind() 方法确定类型后再调用类型的专有方法。

//Int*, Uint* , Float*  , Complex*  : Bits 
//Array : Elem, Len 
//Chan : ChanDir , Elem 
//Func : In , NumIn , Out , NumOut , IsVariadic . 
//Map : Key , Elem 
//Ptr : Elem 
//Slice : Elem 
//Struct : Field, FieldByindex , FieldByName , FieldByNameFunc , NumField 

// 返回类型的元素类型,该方法只适合 Array 、 Chan, Map, Ptr, Slice 类型
Elem() Type
// 返回数值型类型内存占用的位数
Bits() int
// struct 类型专用的方法
// 通过整数索 引获取 struct 字段
Field(i int) StructField
// /获取嵌入字段获取 struct 字段
FieldByIndex(index []int) StructField
// 通过名字查找获取 struct 字段
FieldByName(name string) (StructField, bool)
// func专用字段
// 返回第 i 个输入参数类型
In(i int) Type
// 返回第 i 个返回值类型
Out(i int) Type
// 输入参数个数
NumIn() int
// 返回值个数
NumOut() int
// map 类型专用的方法
// 返回map key 的 type
Key() Type

示例1:

package main

import (
	"fmt"
	"reflect"
)

type Student struct {
	Name string "学生姓名" // tag
	Age  int    `a:"1" b:"2"`
}
type Stu struct {
	a *Stu
	b int
}

func main() {
	var stu Stu
	fmt.Println(stu.a == nil, stu.b == 0)
	rt := reflect.TypeOf(stu)
	// FieldByName;Tag
	if Name, ok := rt.FieldByName("Name"); ok {
		fmt.Println(Name.Tag)
	}
	if Age, ok := rt.FieldByName("Age"); ok {
		fmt.Println(Age.Tag.Get("a"))
		fmt.Println(Age.Tag.Get("b"))
	}
	// rt本身的元信息
	fmt.Println(rt.Name())
	fmt.Println(rt.NumField())
	fmt.Println(rt.PkgPath())
	fmt.Println(rt.String())
	// kind
	fmt.Println(rt.Kind())
	// 换种方式获取所有字段名称
	for i := 0; i < rt.NumField(); i++ {
		fmt.Printf("type.Field[%d].Name:%v \n", i, rt.Field(i).Name)
	}
	// slice
	sc := make([]int, 10)
	sc = append(sc, 1, 2, 3)
	srt := reflect.TypeOf(sc)
	// 元素的type
	ert := srt.Elem()
	fmt.Println(ert.Kind())
	fmt.Printf("%d", ert.Kind())
	fmt.Println(ert.NumMethod())
	fmt.Println(ert.PkgPath())
}

在这里插入图片描述

示例2:

package main

import (
	"fmt"
	"reflect"
)

func main() {
	// int 和 他名int 的当前类型和底层类型
	var a Int = 1
	var b int = 1

	rta := reflect.TypeOf(a)
	rtb := reflect.TypeOf(b)

	fmt.Println(rta == rtb)
	fmt.Println(rta.Kind() == rtb.Kind())
	// 具体类型和接口类型的type
	iA := new(A)
	var sB A = B{}
	var sC C
	rtiA := reflect.TypeOf(iA)
	rtsB := reflect.TypeOf(sB)
	rtsC := reflect.TypeOf(sC)
	//fmt.Println(reflect.TypeOf(rtiA.Field(1)))
	fmt.Println(rtsB.Name())
	fmt.Println(rtsC.Name())
	fmt.Println(rtsB.Kind() == rtsC.Kind())
	fmt.Println(rtiA.Kind())
}

type Int int

type A interface {
	String() string
}
type B struct {
}

func (b B) String() string {
	return "b"
}

type C struct {
}

在这里插入图片描述

二、reflect.Value

reflect.Value 表示实例的值信息, reflect.Value 是一个 struct ,并提供了一系列的 method 给使用者 。

type flag uintptr
type Value struct {
	
	typ *rtype
	
	ptr unsafe.Pointer

	flag
}

refelct. Value 总共有三个字段, 一个是值的类型指针 typ ,另 一个是指向值的指针 ptr , 最后一个是标记字段 flag 。
通过func ValueOf(i interface{}) Value 来获取变量Value的相关信息。

Value结构体提供了丰富的API给用户,简单的示例如下,

package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

type E interface {
	e()
}
type F struct {
	age int
}

func (f *F) e() {

}

func main() {
	user := User{1, 18, "lls"}
	u2 := user
	u2.Id = 1
	fmt.Println(&user == &u2)
	uv := reflect.ValueOf(user)
	uv2 := reflect.ValueOf(&user)
	uv2.Elem().Field(0).Set(reflect.ValueOf(100))
	fmt.Println(uv.CanSet(), uv.FieldByName("Id").CanSet())
	uv2.Elem().Field(0).Set(reflect.ValueOf(100))
	fmt.Println(uv2.CanSet(), uv2.Elem().Field(0).CanSet())
	fmt.Println(uv2.Elem().Field(0), user.Id)
	fmt.Println()
	ut := reflect.TypeOf(user)
	//reflect.PtrTo()
	//a := reflect.New(ut)
	a := reflect.NewAt(ut, unsafe.Pointer(&user))
	fmt.Println(a, reflect.ValueOf(a))
	fmt.Println(uv.Field(0))
	for i := 0; i < uv.NumField(); i++ {
		field := uv.Type().Field(i)
		fieldValue := uv.Field(i).Interface()
		switch val := fieldValue.(type) {
		case int:
			fmt.Println(field.Name, val, field.Type)
		case string:
			fmt.Println(field.Name, val, field.Type)
		}
	}
}

type User struct {
	Id   int
	Age  int
	Name string
}

在这里插入图片描述

总结

1)reflect.Type是封装变量的类型相关信息,reflect.Value是封装变量的值信息。

参考资料

[1] Go 语言核心编程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/375738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PTA L1-058 6翻了(详解)

前言&#xff1a;内容包括&#xff1a;题目&#xff0c;代码实现&#xff0c;大致思路&#xff0c;代码解读 题目&#xff1a; “666”是一种网络用语&#xff0c;大概是表示某人很厉害、我们很佩服的意思。最近又衍生出另一个数字“9”&#xff0c;意思是“6翻了”&#xff0…

vue源码分析-动态组件

前面花了两节的内容介绍了组件&#xff0c;从组件的原理讲到组件的应用&#xff0c;包括异步组件和函数式组件的实现和使用场景。众所周知&#xff0c;组件是贯穿整个Vue设计理念的东西&#xff0c;并且也是指导我们开发的核心思想&#xff0c;所以接下来的几篇文章&#xff0c…

LLaMA-META发布单卡就能跑的大模型

2023年2月25日&#xff0c;Meta使用2048张A100 GPU&#xff0c;花费21天训练的Transformer大模型LLaMA开源了。 1.4T tokenstakes approximately 21 days 以下是觉得论文中重要的一些要点 1&#xff09;相对较小的模型也可以获得不错的性能 研究者发现在给定计算能力限制的情…

【YOLO系列】YOLOv4论文超详细解读1(翻译 +学习笔记)

前言 经过上一期的开篇介绍&#xff0c;我们知道YOLO之父Redmon在twitter正式宣布退出cv界&#xff0c;大家都以为YOLO系列就此终结的时候&#xff0c;天空一声巨响&#xff0c;YOLOv4闪亮登场&#xff01;v4作者是AlexeyAB大神&#xff0c;虽然换人了&#xff0c;但论文中给出…

【BN层的作用】论文阅读 | How Does Batch Normalization Help Optimization?

前言&#xff1a;15年Google提出Batch Normalization&#xff0c;成为深度学习最成功的设计之一&#xff0c;18年MIT团队将原论文中提出的BN层的作用进行了一一反驳&#xff0c;重新揭示BN层的意义 2015年Google团队论文&#xff1a;【here】 2018年MIT团队论文&#xff1a;【h…

谷粒学苑第六天

谷粒学苑第六天 https://hyy-0212.oss-cn-hangzhou.aliyuncs.com/%E5%A4%B4%E5%83%8F.jpg AccessKey看私密文件 后端&#xff1a; idea导入项目后文件颜色不对解决方法 解决&#xff1a;https://blog.csdn.net/m0_37735176/article/details/88916844 后端 私有转为公有&am…

C语言——字符串函数与内存函数

目录 前言 一. 函数介绍 1.1 strlen 1.2 strcpy 1.3 strcat 1.4 strcmp 1.5 strncpy 1.6 strncat 1.7 strncmp 1.8 strstr 1.9 strtok 1.10 strerror 1.11 字符分类函数 1.12 memcpy 1.13 memmove 1.14 memcmp 二. 函数的模拟实现 2.1 模拟实现strlen 2.2 模拟实现st…

阿里测试员晒薪资条,看完真的扎心了...

前几天&#xff0c;有位老粉私信我&#xff0c;说看到某95后学弟晒出阿里的工资单&#xff0c;他是真酸了…想狠补下技术&#xff0c;努力冲一把大厂。 为了帮到他&#xff0c;也为了大家能在最短的时间内做面试复习&#xff0c;我把软件测试面试系列都汇总在这一篇文章了。 …

Windows10 把两张图片合并成一张图片

Windows10把两张图片合并成一张图片 文章目录Windows10把两张图片合并成一张图片1. 背景2. "画图"实现多图拼接1. 背景 相比截图功能&#xff0c;在 Google 的 Chrome 浏览器上&#xff0c;整页截屏功能仍需要安装额外的插件才能完成&#xff0c;这一点 微软的 bing…

【K3s】第18篇 详解 Kubernetes 调度器工作原理

目录 1、概述 2、kube-scheduler 3、kube-scheduler 调度流程 4、支持两种方式配置调度器的过滤和打分行为 4.1 调度策略 4.2 调度策略 5、总结 1、概述 在 Kubernetes 中&#xff0c;调度 是指将Pod放置到合适的节点上&#xff0c;以便对应节点上kubelet能够运行这些 P…

ChatGPT来临,架构师何去何从?

你好&#xff0c;我是李运华。 最近科技圈大火的事件就是ChatGPT的全球火热流行。这款由OpenAI公司在2022年11月底推出的聊天机器人&#xff0c;创造了史上消费应用最快达成1亿用户的历史&#xff0c;在推出仅仅两个月后&#xff0c;月活跃用户估计已达1亿&#xff0c;成为历史…

dbever连接kerberos认证的hive

文章目录一、本地安装kerberos客户端二、本地kerberos客户端登录三、dbever连接hive一、本地安装kerberos客户端 下载地址&#xff1a;https://web.mit.edu/kerberos/dist/index.html 安装&#xff1a;下一步或者自定义安装即可 安装后会自动生成配置文件&#xff1a;C:\Pro…

强化学习RL 01: Reinforcement Learning 基础

目录 RL理解要点 1. RL数学基础 1.1 Random Variable 随机变量 1.2 概率密度函数 Probability Density Function(PDF) 1.3 期望 Expectation 1.4 随机抽样 Random Sampling 2. RL术语 Terminologies 2.1 agent、state 和 action 2.2 策略 policy π 2.3 奖励 reward …

利用GPT-3 Fine-tunes训练专属语言模型

利用GPT-3 Fine-tunes训练专属语言模型 文章目录什么是模型微调&#xff08;fine-tuning&#xff09;&#xff1f;为什么需要模型微调&#xff1f;微调 vs 重新训练微调 vs 提示设计训练专属模型数据准备清洗数据构建模型微调模型评估模型部署模型总结什么是模型微调&#xff0…

cesium: 绘制线段(008)

第008个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中绘制线段,左键点击开始绘制,右键点击取消绘制 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共139行)相关API参考:专栏目标示例效果 配置方式 1)…

Win11的两个实用技巧系列清理磁盘碎片、设置系统还原点的方法

Win11如何清理磁盘碎片?Win11清理磁盘碎片的方法磁盘碎片过多&#xff0c;会影响电脑的运行速度&#xff0c;所以需要定期清理&#xff0c;这篇文章将以Win11为例&#xff0c;给大家分享的整理磁盘碎片方法相信很多用户都会发现&#xff0c;随着电脑使用时间的增加&#xff0c…

一文了解 requestAnimationFrame

requestAnimationFrame 的基本使用 requestAnimationFrame 是什么 window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画&#xff0c;并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数&#xff0c;该回调函数会在浏…

想要实现无人机控制算法二次开发,一定不要错过这个matlab工具包

什么是Matlab工具包 Matlab工具包提供了无人机位置环控制算法、Simulink示例程序&#xff0c;通过Matlab ROS Toolbox建立Matlab&#xff08;Simulink&#xff09;与ROS之间的通信链路&#xff0c;Prometheus项目中将提供转为Matlab设计的控制接口&#xff0c;同时将继承Prome…

Scala-特质

特质 特质的混入用法 特质的叠加 特质和抽象类的区别 特质自身类型 特质 Scala 语言中&#xff0c;采用特质 trait&#xff08;特征&#xff09;来代替接口的概念&#xff0c;也就是说&#xff0c;多个类具有相同 的特质&#xff08;特征&#xff09;时&#xff0c;就可以…

ELK + Kafka 测试

配置file beat输出到 Kafkalogstash服务器从kafka获取数据并输出到es集群在es集群上查看索引kibana界面添加索引查看数据1.配置file beat输出到 Kafka 1.1 Filebeat机器配置数据采集和输出目标 做好域名解析 # vim /usr/local/filebeat/filebeat.yml # 修改输出目标为kafka…