Type and Value

article/2025/9/9 21:45:06

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       uintptrptrdata    uintptr // number of bytes in the type that can contain pointershash       uint32  // hash of type; avoids computation in hash tablestflag      tflag   // extra type information flagsalign      uint8   // alignment of variable with this typefieldAlign uint8   // alignment of struct field with this typekind       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) boolgcdata    *byte   // garbage collection datastr       nameOff // string formptrToThis 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 必须是接口类型的 TypeImplements(u Type) bool// 判断当前类型的实例是否能赋位给 type 为 u 的类型交量AssignableTo(u Type) bool// 判断当前类型的实例是否能强制类型转换为 u 类型交量ConvertibleTo(u Type) bool// 判断当前类型是否支持比较(等 于或不等于)// 支持等于的类型可以作为 map 的 keyComparable() bool// 返回一个类型的方法的个数NumMethod() int// 通过索引位访问方法,索引值必须属于[ 0, NumMethod()],否则引发 panicMethod(int) Method// 通过方法名获取 MethodMethodByName(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 mainimport ("fmt""reflect"
)type Student struct {Name string "学生姓名" // tagAge  int    `a:"1" b:"2"`
}
type Stu struct {a *Stub int
}func main() {var stu Stufmt.Println(stu.a == nil, stu.b == 0)rt := reflect.TypeOf(stu)// FieldByName;Tagif 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())// kindfmt.Println(rt.Kind())// 换种方式获取所有字段名称for i := 0; i < rt.NumField(); i++ {fmt.Printf("type.Field[%d].Name:%v \n", i, rt.Field(i).Name)}// slicesc := make([]int, 10)sc = append(sc, 1, 2, 3)srt := reflect.TypeOf(sc)// 元素的typeert := srt.Elem()fmt.Println(ert.Kind())fmt.Printf("%d", ert.Kind())fmt.Println(ert.NumMethod())fmt.Println(ert.PkgPath())
}

在这里插入图片描述

示例2:

package mainimport ("fmt""reflect"
)func main() {// int 和 他名int 的当前类型和底层类型var a Int = 1var b int = 1rta := reflect.TypeOf(a)rtb := reflect.TypeOf(b)fmt.Println(rta == rtb)fmt.Println(rta.Kind() == rtb.Kind())// 具体类型和接口类型的typeiA := new(A)var sB A = B{}var sC CrtiA := 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 inttype 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 *rtypeptr unsafe.Pointerflag
}

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

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

package mainimport ("fmt""reflect""unsafe"
)type E interface {e()
}
type F struct {age int
}func (f *F) e() {}func main() {user := User{1, 18, "lls"}u2 := useru2.Id = 1fmt.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   intAge  intName string
}

在这里插入图片描述

总结

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

参考资料

[1] Go 语言核心编程


http://chatgpt.dhexx.cn/article/VnLU8vqJ.shtml

相关文章

typescript interface 与 type 声明类型的区别

在 typescript 中, 我们定义类型有两种方式&#xff1a; 接口(interface) 和类型别名(type alias) 在官方文档中我们可以看到: Unlike an interface declaration, which always introduces a named object type, a type alias declaration can introduce a name for any kind…

type是什么

作者&#xff1a;newis 链接&#xff1a;https://www.zhihu.com/question/376890141/answer/1302417252 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 程语言的Type的话&#xff0c;有在不同的场景下有不同的意义…

Type-C

一、Type-C 从USB TYPE-C 的Spec上截一个USB TYPE-C母座的pin脚图&#xff1a; 可以看出&#xff0c;母座上有24根信号&#xff0c; 其中电源和地占据了8根&#xff0c;用于提升电流传输能力&#xff0c;剩下16个&#xff1a; &#xff08;1&#xff09;传输USB3数据的RXx和…

Java Type

Type 是Java 编程语言中所有类型的公共高级接口&#xff08;官方解释&#xff09;&#xff0c;也就是Java 中所有类型的”爹“。其中”所有类型“的描述尤为指的关注。它并不是我们平常工作中经常使用的int、String、List、Map等数据类型&#xff0c;而是从Java语言角度磊说&am…

常见USB接口总结:Type-A、Mini-USB、Micro-USB、Type-C等等

写在前面 最近在整理之前的笔记&#xff0c;打算把一些有价值的笔记发到CSDN分享一下。这篇总结参考的链接如下&#xff0c;结合了自己找的一些图片&#xff0c;非原创&#xff0c;侵权的话私聊我删除。 参考文章链接 https://mb.zol.com.cn/514/5147157.html 总览 标准Type-…

# USB Type-A、Type-B、Type-C及MicroUSB、MiniUSB接口定义

USB Type-A、Type-B、Type-C及MicroUSB、MiniUSB接口定义 文章目录 USB Type-A、Type-B、Type-C及MicroUSB、MiniUSB接口定义1 USB Type-A&#xff08;USB-A&#xff09;2 USB Type-B&#xff08;USB-B&#xff09;3 USB Type-C&#xff08;USB-C&#xff09;3.1 24Pin3.2 16Pi…

Java FileReader相对路径

实验一快要到DDL了&#xff0c;今天在用Javac和Java命令手动执行实验一的代码的时候发现一个问题&#xff0c;当时在IDEA中运行正常的代码&#xff0c;在javac编译手动用java执行的时候发现并不能通过&#xff0c;出问题的代码是一段&#xff08;试图&#xff09;使用相对路径来…

详解HTML的相对路径写法,详解URL相对路径的写法

虽然现在搭网站都会用各种框架&#xff0c;路径方面使用相对路径可能已经比较少了&#xff0c;不过还是总结一下吧。 假设D盘这个路径下有一些文件&#xff1a; D:\例子\html\images\ D:\例子\html\style\ D:\例子\html\example.html D:\例子\html\tupian.gif 1.若引用的资源和…

Python读取相对路径文件

例如下图目录结构: 第一种情况: 1)xxx.py想要打开a.txt,使用相对路径,有如下两种方式: 思路: xxx.py想打开的是b_file下的文件,XXX.py和b_file都在文件目录之下,两者是同级目录,因此操作就是在当前目录向下搜索,因此就可以很容易理解下面的意思了 特别提示:… \是错…

html 的相对路径和绝对路径

整篇文章是以 src 标签进行演示。 文章目录 一、相对路径 1、同级目录查找 2、上一级目录查找 3、下一级目录查找 二、绝对路径 一、相对路径 &#x1f475;相对路径&#xff1a;从当前所处的目录开始查找。 1、同级目录查找 写法&#xff1a; 1.1.直接写文件名&#xf…

java web项目 相对路径怎么写_理解JavaWeb项目中的路径问题——相对路径与绝对路径...

背景:html 在刚开始学习javaweb,使用servlet和jsp开发web项目的过程当中,一直有一个问题困扰着我:servlet 和 jsp 之间相互跳转,跳转的路径应该如何书写,才能正确的访问到相应的servlet或jsp文件?后来,在课堂上,通过老师的讲解,再加上本身的一些思考和实验,终于对we…

相对路径 各种情况

1.相对路径概念 1.1 相对路径就是相对于目标文件或&#xff08;相对虚拟目录&#xff09;的位置。&#xff0c;请看上图&#xff0c;“a.html” 文件里引用了“b.jpg”图片&#xff0c;由于“b.jpg”图片相对于“a.html”来说&#xff0c;是在同一个目录的,那么要在“a.html”文…

java中相对路径怎么写_java中如何使用相对路径读取文件

java中使用相对路径读取文件的方法:1、使用文件【File file = new File(“src/test.txt”)】方法;2、使用类的相对路径;3、使用当前线程的类加载器;4、读取web工程下的文件。 【相关学习推荐: java中使用相对路径读取文件的方法: 一、简单粗暴的 File file = new File(“…

linux 相对路径当前目录,Linux绝对路径和相对路径

前言 在使用linux远程连接操作文件时,我们就会遇到一个问题就是我们必须知道文件的存放位置,才能准确的找到文件并操作文件,在这里指明文件地址就有两种方式,那就是绝对路径和相对路径。 Linux文件目录 我们知道,Linux 系统中所有的文件(目录)都被组织成以根目录“/”开始…

golang 文件操作时相对路径问题

用os包进行Open,Create等操作的时候&#xff0c;需要传入一个path。 这个path 可以是绝对路径&#xff0c; 也可以是相对路径。 这里主要说一下相对路径的坑&#xff0c;在goland的里 // ./是你当前的工程目录&#xff0c;并不是该go文件所对应的目录。 // 比如myPro…

Java io流使用相对路径读取文件

前言&#xff1a; 在大多数时候我们会需要Java程序读取某个文件&#xff0c;不采用绝对路径读取文件&#xff0c;而采用相对路径读取。方法如下&#xff1a; 在工程目录下读取文件&#xff1a; 文件目录&#xff1a; /*** 工程目录下的相对路径读取文件数据*/ public void …

java读取文件相对路径_Java相对路径读取文件

不管你是新手还是老鸟,在程序中读取资源文件总会遇到一些找不到文件的问题,这与Java底层的实现有关,不能算bug,只要方法得当,问题还是可以解决的。 项目的文件夹结构: repathtest ├─src │ └─com │ └─lavasoft │ ├─test │ …

相对路径

相对/绝对路径 顾名思义&#xff0c;相对路径是相对于当前文件的路径。一般是较简短的&#xff0c;那么我们为什么不直接使用绝对路径&#xff0c;也就是文件存放的真实路径&#xff0c;例如&#xff1a;C:\Microsoft\test.txt。 为什么要用相对路径&#xff1f; 当我们把整个…

IDEA FileInputStream 使用相对路径读写文件

最近学习反射机制的时候Properties.load()读取本地文件流的时候怎么也找不到加载文件后面发现IDEA的默认根目录是在它的Project工程下 IDEA 的文件目录和Eclipse 的不一样 同学们可看下图 相当于eclipse的工作空间下 所以就可根据 相对路径 目录 找到文件 上图 一目了然 jus…

C#语言和doNet框架

大家首先要清楚.NET平台与C#不是一回事.这点大家一定要明白,对开发人员来讲他有两个概念。第一,它是C#、VB.net等程序运行的平台。第二,它因为为这些语言提供了丰富的类库(称之为基类库).NET CLR是什么我们现在来一起看看吧。 NET CLR是什么 对于一个将要面向.NET平台进行开发…