这部分是《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)——零散的话题(反射)的更多相关文章

  1. HTML语言学习笔记(会更新)

    # HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...

  2. 2017-04-21周C语言学习笔记

    C语言学习笔记:... --------------------------------- C语言学习笔记:学习程度的高低取决于.自学能力的高低.有的时候生活就是这样的.聪明的人有时候需要.用笨的方法 ...

  3. 2017-05-4-C语言学习笔记

    C语言学习笔记... ------------------------------------ Hello C语言:什么是程序:程序是指:完成某件事的既定方式和过程.计算机中的程序是指:为了让计算机执 ...

  4. GO语言学习笔记(一)

    GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...

  5. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

  6. Go语言学习笔记十三: Map集合

    Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...

  7. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

  8. Go语言学习笔记十一: 切片(slice)

    Go语言学习笔记十一: 切片(slice) 切片这个概念我是从python语言中学到的,当时感觉这个东西真的比较好用.不像java语言写起来就比较繁琐.不过我觉得未来java语法也会支持的. 定义切片 ...

  9. Go语言学习笔记十: 结构体

    Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...

  10. Go语言学习笔记九: 指针

    Go语言学习笔记九: 指针 指针的概念是当时学C语言时了解的.Go语言的指针感觉与C语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...

随机推荐

  1. python实例:解决经典扑克牌游戏 -- 四张牌凑24点 (二)

    Hey! 如果你还没有看这篇的上文的话,可以去稍稍瞅一眼,会帮助加速理解这一篇里面涉及到的递归结构哦!(上一篇点这里:<python实例:解决经典扑克牌游戏 -- 四张牌凑24点 (一)> ...

  2. canvas--总结一

    一.什么是Canvas? HTML5的canvas元素使用JavaScript在网页上绘制图像: 画布是一个矩形区域,可以控制其每一像素: canvas拥有多种绘制路径,矩形,圆形,字符以及添加图像的 ...

  3. docker获取Let's Encrypt永久免费SSL证书

    一 起因 官方的cerbot太烦了,不建议使用 还不如野蛮生长的acme.sh,而这里介绍docker运行cerbot获取Let's Encrypt永久免费SSL证书 二 选型 cerbot的证书不会 ...

  4. NOIP初赛篇——05计算机语言

    程序 ​ 程序就是一系列的操作步骤,计算机程序就是由人实现规定的计算机完成某项工作的操作步骤.每一步骤的具体内容能够理解的指令来描述,这些指令告诉计算机"做什么"和"怎么 ...

  5. 【剑指 Offer】03.数组中重复的数字

    题目描述 找出数组中重复的数字. 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次.请找出数组中 ...

  6. Manjaro Linux 5.9.11-3安装和配置全局截图工具FlameShot教程

    背景说明 截图工具是日常适用频率较高的一种系统工具,在Linux下也有不少常用截图工具,如deepin-screenshot等,但是今天我们要介绍的是FlameShot--一款更加精致的Linux全局 ...

  7. Java开发手册之设计规约

    1.谨慎使用继承的方式来进行扩展,优先使用聚合/组合的方式来实现.说明:不得已使用继承的话,必须符合里氏代换原则,此原则说父类能够出现的地方子类一定能够出现,比如,"把钱交出来", ...

  8. Linux应急响应--入侵排查

    1.入侵者可能会删除机器的日志信息,可以查看日志信息是否还存在或者是否被清空,相关命令示例: ll -h /var/log/*  系统日志一般都存在/var/log下常用的系统日志如下:核心启动日志: ...

  9. 【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 ...

  10. canvas多重阴影发光效果

    canvas多重阴影发光效果 前言 在一个项目中,客户提了一个发光的效果,效果图如下: 阴影 有的人可能会说,这个用阴影其实就可以实现.但是从图中可以看出,是一个比较强烈的发光效果.实际的应用过程中我 ...