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语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...
随机推荐
- Scriptable Render Pipeline
Scriptable Render Pipeline SRP的核心是一堆API集合,使得整个渲染过程及相关配置暴露给用户,使得用户可以精确地控制项目的渲染流程. SRP API为原有的Unity构件提 ...
- CF Grakn Forces 2020 1408E Avoid Rainbow Cycles(最小生成树)
1408E Avoid Rainbow Cycles 概述 非常有趣的题目(指解法,不难,但很难想) 非常崇拜300iq,今天想做一套div1时看见了他出的这套题Grakn Forces 2020,就 ...
- 第二章节 BJROBOT IMU 自动校正 【ROS全开源阿克曼转向智能网联无人驾驶车】
1.把小车平放在地板上,用资料里的虚拟机,打开一个终端 ssh 过去主控端启动roslaunch znjrobot bringup.launch . 2.再打开一个终端,ssh 过去主控端,在 ~/c ...
- Spark学习进度-Spark环境搭建&Spark shell
Spark环境搭建 下载包 所需Spark包:我选择的是2.2.0的对应Hadoop2.7版本的,下载地址:https://archive.apache.org/dist/spark/spark-2. ...
- haproxy 里的超时
haproxy 中的超时 客户端请求阶段 timeout client haproxy 和客户端通信时,连接不活跃的时间,既不发送数据,也不ack接收的数据 如果未设置,则永不超时,此时连接是否超时依 ...
- 双重校验锁 --使用volatile和两次判空校验
介绍 双重校验锁是单例模式中,饿汉式的一种实现方式.因为有两次判空校验,所以叫双重校验锁,一次是在同步代码块外,一次是在同步代码块内. 为什么在同步代码块内还要再检验一次? 第一个if减少性能开销,第 ...
- 【对线面试官】Java NIO
服务端: public class NoBlockServer { public static void main(String[] args) throws IOException { // 1.获 ...
- laravel邮件发送
laravel邮件发送 使用邮件发送类Mail 文本 静态方法 raw() 富文本 静态方法 send() 注:使用邮件发送必须有邮件账号,需要开启smtp协议,现在主流服务器都支持,smtp默认端口 ...
- Windows 2008 Server R2双网卡负载均衡
源文档 <http://blog.sina.com.cn/s/blog_6025f5690101apwd.html>
- SpringBoot嵌入式Servlet容器
SpringBoot默认是将Tomcat作为嵌入式的servlet容器. 问题: 如何修改嵌入式的servlet容器? 1)在配置文件中设置对应的属性值 server.port=8081 # Tomc ...