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语言的没啥不同. 指针定义与使用 指针变量是保存内存地址的变量.其他变量保存的是数值,而指针变量保存的是内存地址.这 ...
随机推荐
- 主从同步遇到 Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'时怎么解决
首先遇到这个是因为binlog位置索引处的问题,不要reset slave: reset slave会将主从同步的文件以及位置恢复到初始状态,一开始没有数据还好,有数据的话,相当于重新开始同步,可能会 ...
- python的22个基本语法
"人生苦短,我用Python".Python编程语言是最容易学习.并且功能强大的语言.只需会微信聊天.懂一点英文单词即可学会Python编程语言.但是很多人声称自己精通Python ...
- Interface注意事项
Interface 成员声明 声明属性,默认static & final 声明方法,默认public interface Instrument { int VALUE = 5; // stat ...
- Bata冲刺——第一天
这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzzcxy/2018SE1 这个作业要求在哪里 https://edu.cnblogs.com/campus/fz ...
- docker frps 内网穿透容器化服务
准备 域名解析 将frp.xx.com解析到服务器ip,将泛域名 *.frp.xx.com解析到frp.xx.com即可 https证书申请 泛域名证书现在可以用acme.sh申请Let's Encr ...
- Angular入门到精通系列教程(6)- Angular的升级
1. 摘要 2. https://update.angular.io/ 3. 总结 环境: Angular CLI: 11.0.6 Angular: 11.0.7 Node: 12.18.3 npm ...
- PHP curl爬取数据 加入cookie值
public function get_cookie(){ header("Content-type:text/html;Charset=utf8"); $ch =curl_ini ...
- 浅谈JVM垃圾回收
JVM内存区域 要想搞懂啊垃圾回收机制,首先就要知道垃圾回收主要回收的是哪些数据,这些数据主要在哪一块区域. Java8和Java8之前的相同点有很多. 都有虚拟机栈,本地方法栈,程序计数器,这三个是 ...
- 如何利用Intellij Idea搭建python编译运行环境 (转)
首先进入Intellij Idea的官方网站:点击打开链接 点击download,选择旗舰版进行下载.网上的破解教程很多,也可以注册一个学生账号拿到一年的免费试用权. 安装过程不再细说,第一次打开选择 ...
- 惠普电脑(HP PHILIPS系列)安装ubuntu后无法连接WIFI解决方案(手动安装8821CE驱动)
一步一步来, 先说环境: 我的电脑是HP PHILIPS系列,ubuntu版本是16.04 背景: win10安装ubuntu后发现无法连接wifi(但win10系统可以连接WIFI),在ubuntu ...