Go语言学习笔记(2)——零散的话题(反射)
这部分是《Go语言编程》这本书的第9章的内容。书中给该章节的定位是一个文章集,其包含了一些Go语言中比较少涉及,或是比较深入的讨论的内容。因为第一节就是反射,而反射在我看来是比较重要的内容,所以就先把这部分内容拿出来看。后续的内容可能会慢慢的补充进来。
2.1 反射
考虑以下例子:
type MyReader struct {
Name string
} func (r MyReader) Read (p []byte) (n int, err error) {
//实现自己的Read方法
} var reader io.Reader
reader = &MyReader("a.txt")
MyReader类型实现了io.Reader接口的所有方法(其实就是read函数),所以MyReader实现了接口io.Reader。
我们对接口进行反射,就可以得到一个包含Type和Value的结构。如果我们对reader进行反射,也将得到一个Type和Value,Type为io.Reader,Value为MyReader("a.txt")。
我们可以这样认为,Type主要表达的是被反射的这个变量本身的类型信息,而Value则为该变量实例本身的信息。
(总体来说我觉得这本书讲反射讲的并不多,而golang的反射又……有点……别扭。所以大概还要加点别的东西,比如:https://blog.csdn.net/fighterlyt/article/details/17360597,这篇讲的还挺清楚的。)
对于任何类型的Go语言对象,类型和值都是其运行时的相关信息,我们可以使用函数TypeOf和ValueOf来获得该对象的值信息。
func TypeOf(i interface{}) Type
func ValueOf(I interface{}) Value
Type类型是一个接口,这个接口实现了String() string方法。Value类型是一个结构体,但是并没有定义任何导出字段。Value类型同样定义了String() string方法。
那么,接下来介绍通用的类型和值所提供的方法,以及常见类型的类型和值提供的方法。这里需要注意,很多方法是由要求的,如果要求不满足的话,就会panic。
通用:
Type
func Align() int func FieldAlign() int |
对齐信息:包括做为变量时的对齐信息和作为一个结构体字段时的对齐信息。 |
func Size() uinptr | 大小:一个该类型的值所存储所需要的内存大小,以字节为单位。 |
func Name() string | 名称:该类型在其定义包中的名称,有些类型没有名称(比如数组等),将返回一个空字符串。 |
func PkgPath() string | 定义位置:该类型的定义位置,就是导入该类型使用的import语句的参数。如果该类型时预定义的(比如string,error等)或者无名的,将返回一个空字符串。 |
func Kind() Kind |
种类:该类型所属的种类。reflect包定义了Kind类型来表示各种类型。注意重命名一个类型并不会改变其种类。Kind类型定义了String() string方法。 Kind的定义包括了: const { Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Unit8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer } |
func NumMethod() int | 方法集:该类型的方法集,Type类型提供了方法来返回方法数量,访问各个方法。reflect包定义了Method类型来表示一个方法。 |
func Method(index int) Method | 使用索引访问方法集。索引从0开始。如果越界则panic。 |
func MethodByName(name string) (Method, bool) | 使用名称访问方法集,bool表明是否找到该方法。 |
func Implements(u Type) bool | 判断是否实现了某接口。其中u表示一个接口类型。 |
func ConvertibleTo(u Type) bool | 判断是否可以使用标准转换语句转换为其他类型。 |
func AssignableTo(u Type) bool | 判断是否可以赋值给其他类型的变量。 |
Value
func (v Value)CanAddr() Value | 判断是否可以获得地址。如果一个值来自以下途径,那么可以获得地址:Slice的一个元素;一个可以获得地址的数组元素;一个可以获得地址的结构体的字段;解引用一个指针的结果。这个方法是反射中设置值的方法的基础。因为在使用ValueOf()生成一个Value时,参数时值传递的。因此设置这个参数的值完全没有意义。正确的方法是传入一个指针,然后调用Elem()方法来生成其指向的元素对应的Value对象。 |
func (v Value)Addr() Value | 获得地址。如果CanAddr()返回false,则会panic。 |
func (v Balue)UnsafeAddr() uintptr | 同样如果CanAddr()返回false,则会panic。 |
func (v Value)CanSet() bool | 是否可以修改值。可以修改值的条件是,必须可以获得地址,并且不能通过访问结构的非导出字段获得。 |
func (v Value)Set(x Value) | 设置值。如果CanSet()返回false,则会panic。 |
func (v Value)Convert(t Type) Value | 转换为其他类型的值。如果无法使用标准Go转换规则来转换,则会panic。 |
func (v Value)Iterface{} interface{} | 以空接口类型获得值。如果Value时通过访问结构体的非到处字段获得,则会panic。 |
func (v Value) IsValid() bool | 是否是一个合法的Value对象。这里注意,只有零值才会返回false。 |
func (v Value)Kind() Kind |
所属的类型分类。注意零值会返回Invalid。 |
func (v Value)NumMethod() int func (v Value)Method(index int) Value func (v Value)MethodByName(name string) Value |
方法集和方法。这里注意,Value和Type虽然定义了同名方法,但是其返回类型是不同的。如果v没有任何方法集,或者索引越界,则会panic。MethodByName方法,如果没有找到名为name的方法,则返回零值。 |
func (v Value)String() string | 字符串格式返回。 |
func (v Value)Type() | Type 类型。 |
以上是通用的Type和Value提供的函数。
对于算术类型的Go对象,有以下方法:
Type
func Bits() int | 位数:返回该类型的大小,以二进制位为单位。 |
Value
func (v Value) Float() float64 func (v Value) Int() int64 func (v Value) Unt() uint64 func (v Value) Complex() complex128 |
获得值。所有的类型使用其对应的方法。 |
func (v Value) SetFloat(x float64) func (v Value) SetInt(x int64) func (v Value) SetUnt(x uint64) func (v Value) SetComplex(x complex128) |
设置值。所有的类型使用其对应的方法。 |
func (v Value) OverflowFloat(x float64) bool func (v Value) OverflowInt(x int64) bool func (v Value) OverflowUnit(x uint64) bool func (v Value) OverflowComplex(x complex128) bool |
辅助设置值:因为每个Set方法都对应了多个对应的具体类型,因此需要一个方法来判断设置值是否够长度。通过判断值检查是否可以存储在对象中而不溢出。 |
结构类型的Go对象
Type
func NumField() int |
结构字段数量。 |
func Field(I int) StructField |
使用索引访问结构字段。索引从0开始。如果越界则panic。 |
func FieldByName(name string) (StructField, bool) |
使用名字访问结构字段。如果未找到返回false。 |
func FieldByNameFunc(match func(string) bool) (StructField, bool) |
访问名字使得match函数返回true的结构字段。注意:同一个内嵌层次上,只能有一个字段使得match返回true。如果同一层次上多个字段使得match返回true,那么这些字段都认为是不符合要求的。 |
func FieldByIndex(index []int) StructField |
该方法用于访问结构的内嵌字段。Index是一个将待访问的各个层次的字段索引排列起来的[]int。若index越界则panic。 |
Value
func (v Value) NumField() int |
结构字段数量 |
func (v Value)Field(I int) Value |
使用索引访问结构字段。索引从0开始。如果越界则panic。 |
func (v Value)FieldByName (name string) Value |
使用名字访问结构字段。如果未找到返回false。 |
func (v Value)FieldByNameFunc (match func(sgring) bool) Value |
访问名字使得match函数返回true的结构字段。注意:同一个内嵌层次上,只能有一个字段使得match返回true。如果同一层次上多个字段使得match返回true,那么这些字段都认为是不符合要求的。 |
func (v Value)FieldByIndex(index []int) Value |
该方法用于访问结构的内嵌字段。Index是一个将待访问的各个层次的字段索引排列起来的[]int。若index越界则panic。 |
总体来说,结构类型的Type和Value提供了几乎相同的方法,仅仅是返回值不同。
Type中,涉及了StructField类型,StructField是一个结构体,其定义如下:
Type StructField struct {
Name string
PkgPath string //对于导出字段,为空字符串;对于非导出字段,是定义该字段类型的包名
Type Type
Tag StructTag //就是结构体字段后面的那个tag
Offset uintptr //在结构体内的位移
Index []int //当使用Type.FieldByIndex()方法时的参数
Anonymous bool //是否为匿名字段
}
方法类型的Go对象:
Type
func IsVariadic() bool |
参数是否可变 |
func NumIn() int func NumOut() int |
参数和返回值的数量。可变参数单独作为slice。 |
func In(i int) Type func Out(i int) Type |
第i个参数/返回值。 |
Value
func (v Value) Call(in []Value) []Value func (v Value) CallSlice(in []Value) []Value |
调用函数。Call()方法用来调用函数(参数可变或者固定),采用的是用户代码使用的调用格式。CallSlice()方法专门用于调用参数可变的函数,它采用了编译器使用的调用格式。这两种调用格式的区别在于:u 对于参数固定的函数,两种格式没有任何区别,都是按照位置,将实参赋予形参;u 对于参数可变的函数,编译器格式会特别处理最后一个参数,将剩余的实参依次放入一个slice内,传递给可变形参的就是这个slice。 |
func (v Value) Pointer() uintptr |
以uintptr返回函数的值,这个值并不能独一无二的识别一个函数,只是保证如果函数为nil,那么这个值为0。 |
未完待续
Go语言学习笔记(2)——零散的话题(反射)的更多相关文章
- HTML语言学习笔记(会更新)
# HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...
- 2017-04-21周C语言学习笔记
C语言学习笔记:... --------------------------------- C语言学习笔记:学习程度的高低取决于.自学能力的高低.有的时候生活就是这样的.聪明的人有时候需要.用笨的方法 ...
- 2017-05-4-C语言学习笔记
C语言学习笔记... ------------------------------------ Hello C语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...
- GO语言学习笔记(一)
GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...
- Haskell语言学习笔记(88)语言扩展(1)
ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...
- Go语言学习笔记十三: Map集合
Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...
- Go语言学习笔记十二: 范围(Range)
Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...
- Go语言学习笔记十一: 切片(slice)
Go语言学习笔记十一: 切片(slice) 切片这个概念我是从python语言中学到的,当时感觉这个东西真的比较好用.不像java语言写起来就比较繁琐.不过我觉得未来java语法也会支持的. 定义切片 ...
- Go语言学习笔记十: 结构体
Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...
- Go语言学习笔记九: 指针
Go语言学习笔记九: 指针 指针的概念是当时学C语言时了解的.Go语言的指针感觉与C语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...
随机推荐
- STM32串口中断的一些资料
在研究STM32串口接收发送中断的时候找到不少不错的资料,现在备份在这里.以供自己查阅,以及方便其他人. TC ====TXE 顺便预告下最近会写个有关串口处理数据的帖子,从查询和中断方面以及数据处理 ...
- eclips如何安装jetty插件
转载自http://www.cnblogs.com/nightswatch/p/4639687.html的博文 eclipse中安装jetty插件并使用 一.eclipse中jetty插件安装: ...
- JavaScript入门-学习笔记(一)
JavaScript入门(一) 学习js之前,我们先来了解一下,什么是JavaScript? JavaScript是一种解释型语言.在运行的时候,一边读一边编译一边执行.简单来说就是,在执行js代码时 ...
- mysql 双主复制 centos7
mysql 安装请看:http://www.cnblogs.com/leohe/p/6839705.html 双主复制设置 1. 两台虚拟机,都是 centos7 主: 10.1.1.115 从: 1 ...
- 最全Java面试题(一)
一.基础篇 1.1 java基础 面向对象的特征:继承.封装和多态 final, finally, finalize 的区别 final用于声明属性.方法和类,分别表示属性不可变.方法不可覆盖.类不可 ...
- Beta冲刺——第五天
这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/2018SE1 这个作业要求在哪里 https://edu.cnblogs.com/campus/fz ...
- TensorFlow中数据读取—如何载入样本
考虑到要是自己去做一个项目,那么第一步是如何把数据导入到代码中,何种形式呢?是否需要做预处理?官网中给的实例mnist,数据导入都是写好的模块,那么自己的数据呢? 一.从文件中读取数据(CSV文件.二 ...
- Spring Boot 2.0 的配置绑定类Bindable居然如此强大
1. 前言 在开发Spring Boot应用时会用到根据条件来向Spring IoC容器注入Bean.比如配置文件存在了某个配置属性才注入Bean : 图中红色的部分是说,只有ali.pay.v1.a ...
- SIGGRAPH Asia 2020 电脑动画节(CAF)获奖短片出炉!
电脑动画节(CAF) 是SIGGRAPH Asia盛会最受瞩目的环节之一.2020年12月15日,SIGGRAPH Asia 2020虚拟线上会议正式宣布了电脑动画节的三部获奖短片:最佳作品奖< ...
- LeetCode141-环形链表检测
题目 给定一个链表,判断链表中是否有环. 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置 ...