反射reflection

  • 反射可大大提高程序的灵活性,使得interface{}有更大的发挥余地
  • 反射使用TypeOf和ValueOf函数从接口中获取目标对象信息
  • 反射会将匿名字段作为独立字段(匿名字段本质)
  • 想要利用反射修改对象状态,前提是interface.data是settable,即pointer-interface
  • 通过反射可以“动态”调用方法

对某一个struct进行反射的基本操作

package main

import (
"fmt"
"reflect"
) type User struct {
Id int
Name string
Age int
} func (u User) Hello() {
fmt.Println("Hello world!")
}
func Info(o interface{}) {
t := reflect.TypeOf(o) //反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息
fmt.Println("Type:", t.Name()) //调用t.Name方法来获取这个类型的名称 v := reflect.ValueOf(o) //打印出所包含的字段
fmt.Println("Fields:")
for i := 0; i < t.NumField(); i++ { //通过索引来取得它的所有字段,这里通过t.NumField来获取它多拥有的字段数量,同时来决定循环的次数
f := t.Field(i) //通过这个i作为它的索引,从0开始来取得它的字段
val := v.Field(i).Interface() //通过interface方法来取出这个字段所对应的值
fmt.Printf("%6s:%v =%v\n", f.Name, f.Type, val)
}
for i := 0; i < t.NumMethod(); i++ { //这里同样通过t.NumMethod来获取它拥有的方法的数量,来决定循环的次数
m := t.Method(i)
fmt.Printf("%6s:%v\n", m.Name, m.Type) }
}
func main() {
u := User{1, "Jack", 23}
Info(u)
}

判断传入的类型是否是我们想要的类型

package main

import (
"fmt"
"reflect"
) type User struct {
Id int
Name string
Age int
} func (u User) Hello() {
fmt.Println("Hello world!")
}
func Info(o interface{}) {
t := reflect.TypeOf(o) //反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息
fmt.Println("Type:", t.Name()) //调用t.Name方法来获取这个类型的名称
if k := t.Kind(); k != reflect.Struct { //通过kind方法判断传入的类型是否是我们需要反射的类型
fmt.Println("xx")
return
}
v := reflect.ValueOf(o) //打印出所包含的字段
fmt.Println("Fields:")
for i := 0; i < t.NumField(); i++ { //通过索引来取得它的所有字段,这里通过t.NumField来获取它多拥有的字段数量,同时来决定循环的次数
f := t.Field(i) //通过这个i作为它的索引,从0开始来取得它的字段
val := v.Field(i).Interface() //通过interface方法来取出这个字段所对应的值
fmt.Printf("%6s:%v =%v\n", f.Name, f.Type, val)
}
for i := 0; i < t.NumMethod(); i++ { //这里同样通过t.NumMethod来获取它拥有的方法的数量,来决定循环的次数
m := t.Method(i)
fmt.Printf("%6s:%v\n", m.Name, m.Type) }
}
func main() {
u := User{1, "Jack", 23}
Info(u)
}

反射 匿名或嵌入字段

package main

import (
"fmt"
"reflect"
) type User struct {
Id int
Name string
Age int
} type Manager struct {
User //反射会将匿名字段作为一个独立字段来处理
Title string
} func main() {
m := Manager{User: User{1, "Jack", 12}, Title: "123"}
t := reflect.TypeOf(m)
fmt.Printf("%#v\n", t.Field(0)) //#号会将reflect的struct的详情页打印出来,可以看出来这是一个匿名字段
fmt.Printf("%#v \n", t.FieldByIndex([]int{0, 0})) //此时 我们就可以将User当中的ID取出来,这里面需要传进方法中的是一个int类型的slice,User相对于manager索引是0,id相对于User索引也是0
fmt.Printf("%v \n", t.FieldByIndex([]int{0, 1}))
v := reflect.ValueOf(m)
fmt.Printf("%#v\n", v.Field(0))
}

通过反射修改struct中的内容

package main

import (
"fmt"
"reflect"
) func main() {
x := 123
v := reflect.ValueOf(&x)
//传递指针才能修改
v.Elem().SetInt(999)
fmt.Println(x)
}
PS G:\mygo\src\mytest> go run .\temp10.go
999
package main

import (
"fmt"
"reflect"
) type User struct {
Id int
Name string
Age int
} func main() {
u := User{1, "Tom", 12}
Set(&u)
fmt.Println(u) } func Set(o interface{}) {
v := reflect.ValueOf(o)
if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {
fmt.Println("xxx")
return
} else {
v = v.Elem()
}
f := v.FieldByName("Name")
if !f.IsValid() {
fmt.Println("xiugaishibai")
}
if f.Kind() == reflect.String {
f.SetString("jACK")
} }

通过发射进行方法的调用 动态调用方法

package main

import (
"fmt"
"reflect"
) type User struct {
Id int
Name string
Age int
} func (u User) Hello(name string) {
fmt.Println("Hello", name, "My name is", u.Name)
} func main() {
u := User{1, "OK", 12}
v := reflect.ValueOf(u)
mv := v.MethodByName("Hello")
args := []reflect.Value{reflect.ValueOf("JOE")}
mv.Call(args)
}

Golang 反射reflection的更多相关文章

  1. [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦

    [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...

  2. [.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程

    [.net 面向对象程序设计进阶] (20) 反射(Reflection)(上)利用反射技术实现动态编程 本节导读:本节主要介绍什么是.NET反射特性,.NET反射能为我们做些什么,最后介绍几种常用的 ...

  3. [整理]C#反射(Reflection)详解

    本人理解: 装配件:Assembly(程序集) 晚绑定:后期绑定 MSDN:反射(C# 编程指南) -----------------原文如下-------- 1. 什么是反射2. 命名空间与装配件的 ...

  4. golang反射初试

    golang反射来自Go AST(Abstract Syntax Tree). reflect操作更多像traverse AST. t := reflect.TypeOf(obj) 使用TypeOf( ...

  5. CSharpGL(43)环境映射(Environment Mapping)-天空盒(Skybox)反射(Reflection)和折射(Refraction)

    CSharpGL(43)环境映射(Environment Mapping)-天空盒(Skybox)反射(Reflection)和折射(Refraction) 开始 如图所示,本文围绕GLSL里的sam ...

  6. 代理(Proxy)和反射(Reflection)

    前面的话 ES5和ES6致力于为开发者提供JS已有却不可调用的功能.例如在ES5出现以前,JS环境中的对象包含许多不可枚举和不可写的属性,但开发者不能定义自己的不可枚举或不可写属性,于是ES5引入了O ...

  7. golang的reflection(转)

    作者:BGbiao 链接:https://www.jianshu.com/p/42c19f88df6c 來源:简书 反射reflection 可以大大提高程序的灵活性,使得interface{}有更大 ...

  8. golang 反射应用(二)

    golang反射应用(二) package test import ( "reflect" "testing" ) //定义适配器 func TestRefle ...

  9. C# 反射(Reflection)技术

    本文参考自C#反射(Reflection)详解,纯属学习笔记,加深记忆 在介绍反射前,先介绍一个重要的知识点         .Net应用程序是由程序集(Assembly).模块(Module).类型 ...

随机推荐

  1. noip第28课作业

    分段数列 [问题描述] 对于给定的一个长度为N的正整数数列A[i],现要将其分成连续的若干段,并且每段和不超过M(可以等于M),问最少能将其分成多少段使得满足要求. 输入格式: 输入第1行包含两个正整 ...

  2. Amoeba常见问题

    1.1.1 JAVA_HOME不认 jdk安装后测试无问题java –version,但启动amoeba就是报错JAVA_HOME找不到.就修改/amoeba/bin/amoeba文件,在文件最开头直 ...

  3. Xcode一些好用的插件,以及这些插件的管理器

    最近从xcode6.4升级到xcode7,发现以前所有的插件都失效了,如果要安装,需要重新去一个个下载.安装,很麻烦. 于是,转来了这篇博文,亲自测试,发现很好用...... 地址:http://11 ...

  4. java 堆排序的实现

    堆就是一个完全二叉树,堆要求是指 该节点大于它的两个子节点.而两个字节点大小不一定. 堆排序的最坏时间复杂度为nlog(n),平均也为nlog(n),占用空间为o(1),是一种比较排序算法. 堆排序也 ...

  5. C++ OCCI API数据库操作之连接、返回查询结果集为json格式

    使用C++操作数据库,转换返回结果集为json格式,易于解析. 以下程序的编译.运行环境:Windows 10 1803.VS2017 17.5.2(vc14).解决方案配置:Release.解决方案 ...

  6. php根据修改时间删除指定目录下文件

    //$dir-文件地址,$files-存储返回数组,$type-查找文件类型组 public function read_dir($dir,&$files,$type) { if(!is_di ...

  7. mysql多列索引

    1,数据库每次查询只能使用一个索引 2,假设数据 表T (a,b,c) rowid 为物理位置rowid a b c(1) 1 1 1(2) 2 1 13(3) 2 2 14(4) 1 3 3(5)  ...

  8. per学习笔记-zkclient,curator使用

    开源客户端,原生api的不足 连接的创建是异步的,需要开发人员自行编码实现等待 连接没有自动的超时重连机制 Zk本身没提供序列化机制,需要开发人员自行指定,从而实现数据的序列化和反序列化 Watche ...

  9. dubbo实现原理之动态编译

    Dubbo为了实现基于spi思想的扩展特性,特别是能够灵活添加额外功能,对于扩展或则策略选择的设配类能够动态生成.对于一些需求已知的类如Protocal,它们的设配类代码dubbo可以直接的提供,但是 ...

  10. Task异步编程,刨根到底

    1. 编译器到底对await做了什么 await 一个异步操作的时候,实际上编译器会创建一个状态机,这个状态机包含了调用者的上下文变量,状态机使用yield迭代器实现,状态机由clr调度,每次运行都会 ...