Go语言中反射的正确使用

介绍

反射是元数据编程的一种形式,指的是程序获得本身结构的一种能力。不同语言的反射模型实现不一样,本文中的反射,仅仅指的是Go语言中的反射模型。

反射有两个问题,在使用前需要三思:

  1. 大量的使用反射会损失一定性能
  2. Clear is better than clever. Reflection is never clear.

Go的类型设计上有一些基本原则,理解这些基本原则会有助于你理解反射的本质:

  1. 变量包括 <type, value> 两部分。理解这一点你就知道为什么nil != nil了。
  2. type包括 static typeconcrete type. 简单来说 static type是你在编码是看见的类型,concrete type是runtime系统看见的类型。
  3. 类型断言能否成功,取决于变量的concrete type,而不是static type. 因此,一个 reader变量如果它的concrete type也实现了write方法的话,它也可以被类型断言为writer.
  4. Go中的反射依靠interface{}作为桥梁,因此遵循原则3. 例如,反射包.Kind方法返回的是concrete type, 而不是static type.

多说无用,下面来看示例代码

代码如下:

package main
 
import (
    "fmt"
    "reflect"
)
 
type T struct {
    A int
    B string
}
 
func main() {
    t := T{23, "skidoo"}
    tt := reflect.TypeOf(t)
    fmt.Printf("t type:%v\n", tt)
    ttp := reflect.TypeOf(&t)
    fmt.Printf("t type:%v\n", ttp)
    // 要设置t的值,需要传入t的地址,而不是t的拷贝。
    // reflect.ValueOf(&t)只是一个地址的值,不是settable, 通过.Elem()解引用获取t本身的reflect.Value
    s := reflect.ValueOf(&t).Elem()
    typeOfT := s.Type()
    for i := 0; i < s.NumField(); i++ {
        f := s.Field(i)
        fmt.Printf("%d: %s %s = %v\n", i,
            typeOfT.Field(i).Name, f.Type(), f.Interface())
    }
}
 
// 输出结果
// t type:main.T
// t type:*main.T
// 0: A int = 23
// 1: B string = skidoo

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

(0)

相关推荐

  • GO语言常用的文件读取方式

    本文实例讲述了GO语言常用的文件读取方式.分享给大家供大家参考.具体分析如下: Golang 的文件读取方法很多,刚上手时不知道怎么选择,所以贴在此处便后速查. 一次性读取 小文件推荐一次性读取,这样程序更简单,而且速度最快. 复制代码 代码如下: func ReadAll(filePth string) ([]byte, error) {  f, err := os.Open(filePth)  if err != nil {   return nil, err  } return iouti

  • Go语言学习笔记之反射用法详解

    本文实例讲述了Go学习笔记之反射用法.分享给大家供大家参考,具体如下: 一.类型(Type) 反射(reflect)让我们能在运行期探知对象的类型信息和内存结构,这从一定程度上弥(mi)补了静态语言在动态行为上的不足.同时,反射还是实现元编程的重要手段. 和 C 数据结构一样,Go 对象头部并没有类型指针,通过其自身是无法在运行期获知任何类型相关信息的.反射操作所需要的全部信息都源自接口变量.接口变量除存储自身类型外,还会保存实际对象的类型数据. func TypeOf(i interface{

  • Go语言struct类型详解

    struct Go语言中,也和C或者其他语言一样,我们可以声明新的类型,作为其它类型的属性或字段的容器.例如,我们可以创建一个自定义类型person代表一个人的实体.这个实体拥有属性:姓名和年龄.这样的类型我们称之struct.如下代码所示: 复制代码 代码如下: type person struct {     name string     age int } 看到了吗?声明一个struct如此简单,上面的类型包含有两个字段. 1.一个string类型的字段name,用来保存用户名称这个属性

  • Go语言的GOPATH与工作目录详解

    GOPATH设置 go 命令依赖一个重要的环境变量:$GOPATH1 (注:这个不是Go安装目录.下面以笔者的工作目录为说明,请替换自己机器上的工作目录.) 在类似 Unix 环境大概这样设置: 复制代码 代码如下: export GOPATH=/home/apple/mygo 为了方便,应该把新建以上文件夹,并且把以上一行加入到 .bashrc 或者 .zshrc 或者自己的 sh 的配置文件中. Windows 设置如下,新建一个环境变量名称叫做GOPATH: 复制代码 代码如下: GOPA

  • go语言通过反射获取和设置结构体字段值的方法

    本文实例讲述了go语言通过反射获取和设置结构体字段值的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: type MyStruct struct {         N int } n := MyStruct{ 1 } // get immutable := reflect.ValueOf(n) val := immutable.FieldByName("N").Int() fmt.Printf("N=%d\n", val) // prints

  • Go语言常用字符串处理方法实例汇总

    本文实例汇总了Go语言常用字符串处理方法.分享给大家供大家参考.具体如下: 复制代码 代码如下: package main import (     "fmt"     "strings"     //"unicode/utf8" ) func main() {     fmt.Println("查找子串是否在指定的字符串中")     fmt.Println(" Contains 函数的用法")    

  • 浅谈Go语言中字符串和数组

    go语言里边的字符串处理和PHP还有java 的处理是不一样的,首先申明字符串和修改字符串 复制代码 代码如下: package main import "fmt" var name string           //申明一个字符串 var emptyname string = "" //申明一个空字符串 func main() {  //申明多个字符串并且赋值  a, b, v := "hello", "word", &

  • 谈谈Go语言的反射三定律

    简介 Reflection(反射)在计算机中表示 程序能够检查自身结构的能力,尤其是类型.它是元编程的一种形式,也是最容易让人迷惑的一部分. 虽然Go语言没有继承的概念,但为了便于理解,如果一个struct A 实现了 interface B的所有方法时,我们称之为"继承". 类型和接口 反射建立在类型系统之上,因此我们从类型基础知识说起. Go是静态类型语言.每个变量都有且只有一个静态类型,在编译时就已经确定.比如 int.float32.*MyType.[]byte. 如果我们做出

  • Go语言创建、初始化数组的常见方式汇总

    本文实例总结了Go语言创建.初始化数组的常见方式.分享给大家供大家参考.具体分析如下: Go语言的语法很灵活,以下展示了创建并初始化数组的多种方式: 复制代码 代码如下: //数组初始化的各种方式  func arraySliceTest0201() {      //创建数组(声明长度)      var array1 = [5]int{1, 2, 3}      fmt.Printf("array1--- type:%T \n", array1)      rangeIntPrin

  • Go语言中使用反射的方法

    本文实例讲述了Go语言中使用反射的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: // Data Model type Dish struct {   Id  int   Name string   Origin string   Query func() } 创建实例如下: 复制代码 代码如下: shabushabu = Dish.new shabushabu.instance_variables # => [] shabushabu.name = "Shabu-S

随机推荐