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

Type and Value相关推荐

  1. redisson get()数据报错,missing type id property ‘@class’

    redisson get()数据报错: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when ...

  2. mybatis查询报错:com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from string

    mybatis查询报错: com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from strin ...

  3. restTemplate http请求报错:no suitable HttpMessageConverter found for response type and content type

    报错信息: org.springframework.web.client.UnknownContentTypeException: Could not extract response: no sui ...

  4. Oracle type (自定义类型的使用)

    oracle - type type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要 ...

  5. 非本地类型不能定义方法 cannot define new methods on non-local type time.Duration

    能够随意地为各种类型起名字,是否意味着可以在自己包里为这些类型任意添加方法 ? 参见下面的代码演示 : package mainimport "time"type MyDurati ...

  6. 安装 sklearn 报错 ImportError: cannot import name Type

    1. 安装 sklearn sudo pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple sklearn 会默认安装 joblib , s ...

  7. RuntimeError: Expected object of device type cuda but got device type cpu for argument pytorch数据位置

    RuntimeError: Expected object of device type cuda but got device type cpu for argument #2 'target' i ...

  8. 全面理解Python中的类型提示(Type Hints)

    众所周知,Python 是动态类型语言,运行时不需要指定变量类型.这一点是不会改变的,但是2015年9月创始人 Guido van Rossum 在 Python 3.5 引入了一个类型系统,允许开发 ...

  9. Python type hints 之 Optional,Union

    1,前言 type hint 在pep484加入,我个人觉得这种类似于类型约束的(机制)有点违背了python简单.简洁的初衷,在慢慢向c# java 这种强类型语言看齐的节奏. 不过好在不强制使用, ...

  10. Go 学习笔记(33)— Go 自定义类型 type(自定义结构体、结构体初始化、结构体内嵌、自定义接口)

    1. 自定义类型格式 用户自定义类型使用关键字 type ,其语法格式是: type newType oldType oldType 可以是自定义类型.预声明类型.未命名类型中的任意一种. newTy ...

最新文章

  1. 死磕Java并发:J.U.C之阻塞队列:LinkedBlockingDeque
  2. java判断邮箱名和文件名_Java公开课|想学好Java,教你操作Java校验文件名和邮箱地址,快来看看...
  3. Redis基础高级学习笔记
  4. python:how does subclass call baseclass's __init__()
  5. HihoCoder - 1591 锦标赛(最大费用最大流)
  6. Python 函数式编程,Python中内置的高阶函数:map()、reduce()、filter()与sorted(),Python中返回函数
  7. SAP Business Application Studio 如何同 SAP BTP CloudFoundry 环境绑定
  8. SAP Spartacus里Product Carousel componentData取数据的逻辑研究
  9. 使用 jQuery Mobile 与 HTML5 开发 Web App —— jQuery Mobile 默认配置与事件基础
  10. scala的数值类型(三)
  11. AD DS 域控与成员计算机的时间一致性
  12. 层次选择器[selector_2.html]
  13. 如何搜mac_今日头条号权重怎么查?如何提高头条号权重?看完这篇你就懂了
  14. 超星尔雅学习通情商与智慧人生 答案 满分版
  15. 机械计算机辅助设计考研,华科机械考研
  16. Java Instrument 功能使用及原理
  17. 博通无线网卡驱动 linux,debian 安装博通无线网卡驱动
  18. 手把手教你玩转 Gitea|使用 Helm 在 K3s 上安装 Gitea
  19. 呼叫中心系统和外呼机器人的高效组合
  20. 失业登记对养老保险是否有影响

热门文章

  1. pngquant php,pngquant PHP示例不起作用
  2. 一图归纳三大种类矩阵范数:诱导范数,元素范数,Schatten范数,涵盖谱范数,2范数
  3. 在VS2010中去掉ipch和sdf文件方法
  4. 实现邮箱验证(邮箱验证码登录)
  5. 4月累计视频号涨粉10W+
  6. python e_python里面e符号代表什么?
  7. BT技术常用术语介绍
  8. python 折线图 百分比_Excel柱状图折线图组合怎么做 Excel百分比趋势图制作教程...
  9. 计算机网络【性能指标之速率、带宽、吞吐量、时延、时延带宽积、往返时延RTT、利用率】
  10. 【Node.js实战】一文带你开发博客项目之Express重构(博客的增删查改、morgan写日志)