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语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...
随机推荐
- python实例:解决经典扑克牌游戏 -- 四张牌凑24点 (二)
Hey! 如果你还没有看这篇的上文的话,可以去稍稍瞅一眼,会帮助加速理解这一篇里面涉及到的递归结构哦!(上一篇点这里:<python实例:解决经典扑克牌游戏 -- 四张牌凑24点 (一)> ...
- canvas--总结一
一.什么是Canvas? HTML5的canvas元素使用JavaScript在网页上绘制图像: 画布是一个矩形区域,可以控制其每一像素: canvas拥有多种绘制路径,矩形,圆形,字符以及添加图像的 ...
- docker获取Let's Encrypt永久免费SSL证书
一 起因 官方的cerbot太烦了,不建议使用 还不如野蛮生长的acme.sh,而这里介绍docker运行cerbot获取Let's Encrypt永久免费SSL证书 二 选型 cerbot的证书不会 ...
- NOIP初赛篇——05计算机语言
程序 程序就是一系列的操作步骤,计算机程序就是由人实现规定的计算机完成某项工作的操作步骤.每一步骤的具体内容能够理解的指令来描述,这些指令告诉计算机"做什么"和"怎么 ...
- 【剑指 Offer】03.数组中重复的数字
题目描述 找出数组中重复的数字. 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次.请找出数组中 ...
- Manjaro Linux 5.9.11-3安装和配置全局截图工具FlameShot教程
背景说明 截图工具是日常适用频率较高的一种系统工具,在Linux下也有不少常用截图工具,如deepin-screenshot等,但是今天我们要介绍的是FlameShot--一款更加精致的Linux全局 ...
- Java开发手册之设计规约
1.谨慎使用继承的方式来进行扩展,优先使用聚合/组合的方式来实现.说明:不得已使用继承的话,必须符合里氏代换原则,此原则说父类能够出现的地方子类一定能够出现,比如,"把钱交出来", ...
- Linux应急响应--入侵排查
1.入侵者可能会删除机器的日志信息,可以查看日志信息是否还存在或者是否被清空,相关命令示例: ll -h /var/log/* 系统日志一般都存在/var/log下常用的系统日志如下:核心启动日志: ...
- 【Problem】前端项目运行:Module build failed:Error Node Sass does not yet support my current environmen
我在运行renren-fast-vue前端项目时,安装完依赖cnpm install 启动服务npm run dev 出现问题. Module build failed: Error: Node Sa ...
- canvas多重阴影发光效果
canvas多重阴影发光效果 前言 在一个项目中,客户提了一个发光的效果,效果图如下: 阴影 有的人可能会说,这个用阴影其实就可以实现.但是从图中可以看出,是一个比较强烈的发光效果.实际的应用过程中我 ...