GO_09:GO语言基础之reflect反射
反射reflection
1. 反射可以大大的提高程序的灵活性,使得 interface{} 有更大的发挥余地
2. 反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息
3. 反射会将匿名字段作为独立字段(匿名字段本质)
4. 想要利用反射修改对象状态,前提是 interface.data 是 settable,即 pointer-interface
5. 通过反射可以“动态”调用方法
示例一:
举例说明反射使用 TypeOf 和 ValueOf 来取得传入类型的属性字段于方法
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) //获取接受到到接口到类型
fmt.Println("Type:", t.Name()) //打印对应类型到名称(这是reflect中自带到) //Kind()方法是得到传入类型到返回类型;下面执行判断传入类型是否为一个结构体
if k := t.Kind(); k != reflect.Struct {
fmt.Println("传入的类型有误,请检查!")
return
} v := reflect.ValueOf(o) //获取接受到到接口类型包含到内容(即其中到属性字段和方法)
fmt.Println("Fields:") //如何将其中到所有字段和内容打印出来呢?
/**
通过接口类型.NumField 获取当前类型所有字段个数
*/
for i := ; i < t.NumField(); i++ {
f := t.Field(i) //取得对应索引的字段
val := v.Field(i).Interface() //取得当前字段对应的内容
fmt.Printf("%6s: %v = %v\n", f.Name, f.Type, val)
}
/**
通过接口类型.NumMethod 获取当前类型所有方法的个数
*/
fmt.Println("Method:")
for i := ; i < t.NumMethod(); i++ {
m := t.Method(i) //取得对应索引的方法
fmt.Printf("%6s: %v\n", m.Name, m.Type)
}
} func main() {
u := User{, "OK", }
Info(u)
//Info(&u) 如果传入的是结构体的地址或指针(pointer-interface),那么在Info函数中的Kind方法进行判断时就会被拦截返回
}
运行结果如下:
Type: User
Fields:
Id: int = 1
Name: string = OK
Age: int = 12
Method:
Hello: func(main.User)
示例二:
如何通过反射得道结构当中匿名或者嵌入字段
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{, "OK", }, title: ""}
t := reflect.TypeOf(m) //取得类型中的字段是否为匿名字段
fmt.Printf("%6v\n", t.Field())
/**
打印内容:{User main.User 0 [ 0] true},其中true表示是匿名类型
那么想要取匿名类型中的字段又该怎么取呢?这里需要使用序号组,传入要取的切片即可
*/
fmt.Printf("%v\n", t.FieldByIndex([]int{, }))
/**
其中上面切片传入的是{0, 0},
1. 第一个0表示当前结构Manager取匿名User是第一个即为0
2. 第二个0表示取得的结构User中要取第一个元素Id相对于User来说也是第一个即为0,如果要取Name则需传入[]int{0, 1}
那么既然可以取出来内容,那么我们就可以尝试着进行修改,怎么做呢?
*/
tchage := reflect.ValueOf(&m) //想要修改和我们之前所说的传入值类型和指针类型是一致的,要想修改需要传入对应指针类型
tchage.Elem().FieldByIndex([]int{, }).SetInt() //传入指针需要通过 .Elem() 来取得对应的值内容,之后再想取哪个再继续使用序号组
fmt.Println(tchage.Elem().FieldByName("title"))
fmt.Println(tchage)
}
运行结果:
{ User main.User 0 [ 0] true}
{Id int 0 [0] false}
123
&{{999 OK 15} 123}
示例三:
那么让我们来写一个比较完整的通过反射修改结构体内部字段内容
package main import (
"fmt"
"reflect"
) //定义一个用户结构体
type User struct {
Id int
Name string
Age int
} func main() {
u := User{, "OK", }
fmt.Println(u)
Set(&u)
fmt.Println(u)
} //定义一个可以接受任何类型的空接口
func Set(o interface{}) {
v := reflect.ValueOf(o)
//通过反射修改类型中的内容需要传入指针,为了防止传入有误故在这里进行相关过滤验证判断(这前这快是已经说过的)
if v.Kind() == reflect.Ptr && !v.Elem().CanSet() {
//reflect.Ptr对应为指针类型;v.Elem().CanSet()取得对应地址下的内容并查看其是否可以进行修改
fmt.Println("传入的类型有误,请检查!")
return
} else {
v = v.Elem() //将实际对象(包含详情内容)进行赋值
} f := v.FieldByName("Name")
f1 := v.FieldByName("Id1")
if !f.IsValid() { //判断通过名称获取得到到内容是否为空值
fmt.Println("没有Name对应属性字段")
return
}
if !f1.IsValid() {
fmt.Println("没有Id1对应属性字段")
}
if f.Kind() == reflect.String {
f.SetString("HelloWorld")
}
}
运行结果:
{1 OK 13}
没有Id1对应属性字段
{1 HelloWorld 13}
示例四:
那么让我们来写一个比较完整的通过反射对方法等动态调用
package main import (
"fmt"
"reflect"
) //定义一个用户结构体
type User struct {
Id int
Name string
Age int
} //为User绑定方法
func (u User) HelloDisplay(name string) {
fmt.Println("Hello", name, " my name is ", u.Name)
} func main() {
u := User{, "OK", }
u.HelloDisplay("jack") //正常调用 /**
以下方式为反射调用,最优到代码写法就是新写一个方法且在开始是通过kind判断类型是否正确且需要判断有没有对应方法等
*/
v := reflect.ValueOf(u) //通过反射得到类型内容
methodV := v.MethodByName("HelloDisplay") //通过方法名称得道方法实体
args := []reflect.Value{reflect.ValueOf("jack")} //设置反射传入的参数
methodV.Call(args)
}
运行结果:
Hello jack my name is OK
Hello jack my name is OK
GO_09:GO语言基础之reflect反射的更多相关文章
- GO语言基础之reflect反射
反射reflection 1. 反射可以大大的提高程序的灵活性,使得 interface{} 有更大的发挥余地 2. 反射使用 TypeOf 和 ValueOf 函数从接口中获取目标对象信息 3. 反 ...
- Go语言基础之反射
Go语言基础之反射 本文介绍了Go语言反射的意义和基本使用. 变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息. 值信息:程序运行过程中可动态变化的. 反射介绍 反射是指 ...
- GO学习-(17) Go语言基础之反射
Go语言基础之反射 本文介绍了Go语言反射的意义和基本使用. 变量的内在机制 Go语言中的变量是分为两部分的: 类型信息:预先定义好的元信息. 值信息:程序运行过程中可动态变化的. 反射介绍 反射是指 ...
- 黑马程序猿————Java基础日常笔记---反射与正則表達式
------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 黑马程序猿----Java基础日常笔记---反射与正則表達式 1.1反射 反射的理解和作用: 首 ...
- Java基础13:反射与注解详解
Java基础13:反射与注解详解 什么是反射? 反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性. Orac ...
- Go 语言基础
Go 语言基础 特点 常用命令 go run 直接运行, 不会生成可执行文件 go build 生成可执行文件, 推荐 加分特点 UTF-8编码 高并发: go 关键字 管道: pipe := mak ...
- goweb-go语言基础
go语言基础 虽然这本书是讲goweb,但还是吧go语言基础过了一遍,由于我之前已经对go语言基础做了一遍系统的学习,这里就当简单回顾一下,不再写过多笔记了,之前的写的博客都有基础知识,O(∩_∩)O ...
- GO学习-(20) Go语言基础之单元测试
Go语言基础之单元测试 不写测试的开发不是好程序员.我个人非常崇尚TDD(Test Driven Development)的,然而可惜的是国内的程序员都不太关注测试这一部分. 这篇文章主要介绍下在Go ...
- Go语言基础之结构体
Go语言基础之结构体 Go语言中没有“类”的概念,也不支持“类”的继承等面向对象的概念.Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性. 类型别名和自定义类型 自定义类型 在G ...
随机推荐
- java实验三 敏捷开发与XP实践
一.实验内容 (一)敏捷开发与XP 软件开发流程的目的是为了提高软件开发.运营.维护的效率,并提高软件的质量.用户满意度.可靠性和软件的可维护性. 光有各种流程的思想是不够的,我们还要有一系列的工具来 ...
- Servlet学习小结
最近有点小累啊,上课平均一天6小时,再去修一修代码就没什么多的时间了.现在写我最近学习的成果:想想最近软件工程老师留的题目,我还有一些重要的地方没有想清楚.题目是这样的:生成四则运算的题目,算术题目包 ...
- 第二阶段Sprint1
昨天:进行第二阶段第一次站立会议,讨论冲刺阶段,目标,任务认领 今天:实现视频录制,共享平台的视频下载和上传 遇到的问题:调手机摄像头没问题,共享平台怎么办
- NodeJs异步的执行过程
我这里写了一个代码片段,用来模拟一个嵌套的异步过程,下面我总结了下这段代码的执行顺序var fs = require("fs"); fs.stat('a.txt',callback ...
- angularJS1笔记-(6)-自定义过滤器
html: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- 关于Keil C51中“ERROR L107: ADDRESS SPACE OVERFLOW ”的总
最近写一个关于单片机播放音乐的程序,出现如下错误: *** ERROR L107: ADDRESS SPACE OVERFLOW ... ... Program Size: data=167.6 xd ...
- 个人作业-Week 2
一.代码复审 概要部分 代码能符合需求和规格说明么? 能: 代码设计是否有周全的考虑? 有较为周全的考虑: 代码可读性如何? 可读性一般: 代码容易维护么? 不太容易维护: 代码的每一行都执行并检查过 ...
- [2017BUAA软工]个人项目心得体会:数独
心得体会 回顾此次个人项目,感受比较复杂,最明显的一点是--累!代码编写.单元测试.代码覆盖.性能优化,环环相扣,有种从作业发布开始就一直在赶DDL的感觉,但是很充实,也学习到和体验了很多东西.最令人 ...
- fir.im的高级统计功能
fir.im的高级统计功能,可以根据渠道和活动名称,统计不同渠道和活动带来的下载量.操作步骤如下: 第一步:生成统计链接 点击高级统计,进入统计详情页,然后点击生成统计链接: 设置统计链接的应用版本. ...
- vmware 已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。
错误提示:已将该虚拟机配置为使用 64 位客户机操作系统.但是,无法执行 64 位操作. 此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态. 如果已在 BIOS/固件设置中禁用 ...