Go反射机制Reflect

和Java语言一样,Go也实现运行时反射,这为我们提供一种可以在运行时操作任意类型对象的能力。Go是静态类型化的。每个变量都有一个静态类型,也就是说,在编译的时候变量的类型就被很精确地确定下来了,比如要么是int,或者是float32,或者是MyType类型,或者是[]byte等等。
1、第一反射定律(接口值到反射对象的反射)TypeOf和ValueOf在Go的反射定义中,任何接口都会由两部分组成的,一个是接口的具体类型,一个是具体类型对应的值。比如var i int = 3 ,因为interface{}可以表示任何类型,所以变量i可以转为interface{},所以可以把变量i当成一个接口,那么这个变量在Go反射中的表示就是<Value,Type>,其中Value为变量的值3,Type变量的为类型int。reflect.Typeof获取具体的类型;reflect.Valueof获取接口的value。
type Myint int
type User struct {
name string
age int
}
func main() {
u := User{name:"lyd",age:24}
var num Myint = 18
t := reflect.TypeOf(u) //main.User
v := reflect.ValueOf(u) //{lyd 24}
t_num := reflect.TypeOf(num) //main.Myint
v_num := reflect.ValueOf(num) //18
}
//还可以这样打印
fmt.Printf("%T\n",u)
fmt.Printf("%v\n",u)
v.Type() //main.User

#go#
追加内容 2019-01-08 15:01:38
2、将reflect.Value转原始类型(第二反射定律)
上面的例子我们可以通过reflect.ValueOf函数把任意类型的对象转为一个reflect.Value,给定一个reflect.Value,我们能用Interface方法把它恢复成一个接口值;
type Myint int
type User struct {
name string
age int
}
func main() {
u := User{name:"lyd",age:24}
var num Myint = 18
v := reflect.ValueOf(u)
v_num := reflect.ValueOf(num)
y := v.Interface().(User)
//fmt.Println可以处理interface{}, 所以可以直接
y_num := v_num.Interface()
fmt.Println(y,y_num) //{lyd 24} 18
}

3、修改反射对象的值(第三反射定律)
reflect.ValueOf函数返回的是一份值的拷贝,所以前提是我们是传入要修改变量的地址。 其次需要我们调用Elem方法找到这个指针指向的值。Value为我们提供了CanSet方法可以帮助我们判断Value的settablity 一:反射对象不是settable的
func main() {
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1) // Error: will panic.
}
func main() {
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet()) //settability of v: false
}
var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.注意这里哦!我们把x地址传进去了!
fmt.Println("type of p:", p.Type()) // type of p: *float64
fmt.Println("settability of p:", p.CanSet()) //settability of p: false

反射对象p不是settable的,但是我们想要设置的不是p,而是(效果上来说)*p。为了得到p指向的东西,我们调用Value的Elem方法

二:总之,下面这样才是可以改变值的
func main() {
x:=2
v:=reflect.ValueOf(&x)
v.Elem().SetInt(100)
fmt.Println(x)
}

4、获取底层类型
type User struct {
name string
age int
}
func main() {
u := User{name:"lyd",age:24}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
fmt.Println(t.Kind(),v.Kind()) //struct struct
}

5、遍历字段和方法
通过反射,我们可以获取一个结构体类型的字段,也可以获取一个类型的导出方法
type User struct {
name string
age int
}
func main() {
u := User{name:"lyd",age:24}
t := reflect.TypeOf(u)
for i:=0;i<t.NumField();i++ {
fmt.Println(t.Field(i).Name)
}
}
//name
//age

//方法
for i:=0;i<t.NumMethod() ;i++ {
fmt.Println(t.Method(i).Name)
}

追加内容 2019-01-08 15:06:45
6,反射获取字段tag
func main() {
user := User{Name:"lyd",Age:22}
t := reflect.TypeOf(user)
for i:=0;i<t.NumField();i++ {
idx := t.Field(i)
fmt.Println(idx.Tag)
}
}
//name
//age
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
user := User{Name:"lyd",Age:22}
t := reflect.TypeOf(user)
for i:=0;i<t.NumField();i++ {
idx := t.Field(i)
fmt.Println(idx.Tag.Get("json"))
}
}
//name
//age

评论2

  • 2019 i come

    2019-01-08 14:59:00 回复
  • 快捷键	作用	备注
    ctrl + n 导航到类名
    ctrl + shift + n 导航到文件
    ctrl + e/ctrl + shift + e 打开到最近的文件/打开最近修改的文件
    ctrl + shift + i 简短地查看源定义
    ctrl + alt + m 重构表达式为函数 光标在表达式的末尾
    ctrl + space 快速返回实现 return 字段后使用
    ctrl+ shift+ a 工具调用 如 go tools,restful 等
    ctrl + shift + space 智能类型推断式返回 return 字段后使用
    ctrl + i 实现某接口 见图
    ctrl + p 查看 method 参数信息 见图
    ctrl + shift + p 查看表达式类型 见图
    ctrl + alt + v 自动生成表达式返回值 见图
    alt + j 相同单词多选 类似 sublime Ctrl + D
    图示
    ctrl + i 实现某接口(在 type struct 上使用)
    ctrl + p 查看方法参数信息(在方法括号中使用)
    ctrl + shift + p 查看表达式类型(在表达式上或者表达式末尾使用)
    alt + enter 会出现一些 intention的操作(比如在第三方包名上使用,可以添加 import 包别名)
    ctrl + alt + v 生成表达式返回值(表达式末尾使用。先不要写 “resp, err :=”,按下快捷键后会自动生成。)
    Alt + J 类似 sublime 上的 Ctrl + D 多选 (此外还有 Shift + Ctrl + Alt + J, Alt + Shift + Mouse Click,可以实现多选 )
    文件相关快捷键:
    CTRL+E,打开最近浏览过的文件。
    CTRL+SHIFT+E,打开最近更改的文件。
    CTRL+N,可以快速打开struct结构体。
    CTRL+SHIFT+N,可以快速打开文件。
    代码格式化:
    CTRL+ALT+T,可以把代码包在一个块内,例如if{…}else{…}。
    CTRL+ALT+L,格式化代码。
    CTRL+空格,代码提示。
    CTRL+/,单行注释。CTRL+SHIFT+/,进行多行注释。
    CTRL+B,快速打开光标处的结构体或方法(跳转到定义处)。
    CTRL+“+/-”,可以将当前方法进行展开或折叠。
    查找和定位
    CTRL+R,替换文本。
    CTRL+F,查找文本。
    CTRL+SHIFT+F,进行全局查找。
    CTRL+G,快速定位到某行。
    代码编辑
    ALT+Q,可以看到当前方法的声明。
    CTRL+Backspace,按单词进行删除。
    SHIFT+ENTER,可以向下插入新行,即使光标在当前行的中间。
    CTRL+X,删除当前光标所在行。
    CTRL+D,复制当前光标所在行。
    ALT+SHIFT+UP/DOWN,可以将光标所在行的代码上下移动。
    CTRL+SHIFT+U,可以将选中内容进行大小写转化。
    CTRL+SHIFT+SPACE,自动补全代码
    ALT+ENTER 检查并修复
    CTRL+O,实现接口的所有方法
    界面切换
    ALT+1,打开/关闭Project窗口
    ALT+2,打开/关闭Favorites窗口
    ALT+7,打开文件方法列表
    ---------------------
    https://github.com/golang/protobuf
    https://github.com/fananchong/cstruct-go

    2019-01-08 15:09:04 回复
评论请先登录

最近热帖

  1. PPS代理节点池 69586
  2. PPS代理节点池② 26675
  3. 订阅池记录 8000
  4. 基于 Harbor 搭建 Docker 私有镜像仓库 6440
  5. V2ray免费账号 2354
  6. PPS代理节点池③ 2189
  7. 全栈开发笔记 1664
  8. 百度的无刷新搜索之PJAX 1572
  9. css之rem布局(rem.js) 1491
  10. docker swarm 集群高可用 1308

近期热议

  1. GITHUB项目 55
  2. PPS代理节点池 50
  3. WEB代理地址 43
  4. 全栈开发笔记 42
  5. ROBOT机器人之路 31
  6. C++回归之路 19
  7. OCR识别探索 16
  8. PPS代理节点池② 14
  9. DB到ES同步之路 11
  10. 接码平台地址 9