Type and Value

文章详细介绍了Go语言中的反射库reflect的核心类型reflect.Type和reflect.Value。reflect.Type用于获取变量的类型信息,包括数据结构、通用方法以及特定类型的专有方法。reflect.Value则关注变量的值,提供了访问和修改值的API。文章通过示例代码展示了如何使用这两个类型进行类型检查、类型转换和值操作。
摘要由CSDN通过智能技术生成

前言

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 语言核心编程

【6层】一字型框架办公楼(含建筑结构图、计算书) 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值