Go语言中反射的正确使用_Golang

介绍

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

总结

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

时间: 2024-10-27 03:14:46

Go语言中反射的正确使用_Golang的相关文章

Go语言中错误处理实例分析_Golang

本文实例讲述了Go语言中错误处理的方法.分享给大家供大家参考.具体分析如下: 错误是可以用字符串描述自己的任何东西. 主要思路是由预定义的内建接口类型 error,和其返回返回字符串窜的方法 Error 构成. type error interface { Error() string } 当用 fmt 包的多种不同的打印函数输出一个 error 时,会自动的调用该方法. 复制代码 代码如下: package main import (     "fmt"     "time

go语言中时间戳格式化的方法_Golang

本文实例讲述了go语言中时间戳格式化的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: var t int64 = time.Now().Unix() var s string = time.Unix(t, 0).Format("2006-01-02 15:04:05") println(s) 这方式比较特别,按照123456来记忆吧:01月02号 下午3点04分05秒 2006年 希望本文所述对大家的Go语言程序设计有所帮助.

举例讲解Go语言中函数的闭包使用_Golang

和变量的声明不同,Go语言不能在函数里声明另外一个函数.所以在Go的源文件里,函数声明都是出现在最外层的. "声明"就是把一种类型的变量和一个名字联系起来. Go里有函数类型的变量,这样,虽然不能在一个函数里直接声明另一个函数,但是可以在一个函数中声明一个函数类型的变量,此时的函数称为闭包(closure). 例: 复制代码 代码如下: packagemain   import"fmt"   funcmain(){     add:=func(baseint)fun

深入理解Go语言中的数组和切片_Golang

一.类型 数组是值类型,将一个数组赋值给另一个数组时,传递的是一份拷贝. 切片是引用类型,切片包装的数组称为该切片的底层数组. 我们来看一段代码 //a是一个数组,注意数组是一个固定长度的,初始化时候必须要指定长度,不指定长度的话就是切片了 a := [3]int{1, 2, 3} //b是数组,是a的一份拷贝 b := a //c是切片,是引用类型,底层数组是a c := a[:] for i := 0; i < len(a); i++ { a[i] = a[i] + 1 } //改变a的值后

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

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

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

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

Go语言中的内存布局详解_Golang

一.go语言内存布局 想象一下,你有一个如下的结构体. 复制代码 代码如下: type MyData struct {         aByte   byte         aShort  int16         anInt32 int32         aSlice  []byte } 那么这个结构体究竟是什么呢? 从根本上说,它描述了如何在内存中布局数据. 这是什么意思?编译器又是如何展现出来呢? 我们来看一下. 首先让我们使用反射来检查结构中的字段. 二.反射之上 下面是一些使用

C语言中正确使用const

基本解释 const是一个C语言的关键字,它限定一个变量不允许被改变.使用const在一定程度上可以提高程序的健壮性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助. 虽然这听起来很简单,但实际上,const的使用也是c语言中一个比较微妙的地方,微妙在何处呢?请看下面几个问题. 问题:const变量 & 常量 为什么我象下面的例子一样用一个const变量来初始化数组,ANSI C的编译器会报告一个错误呢? const int n = 5; int a[n]

Go语言中关闭带缓冲区的频道实例分析_Golang

本文实例分析了Go语言中关闭带缓冲区的频道.分享给大家供大家参考.具体分析如下: Go语言提供了两种频道,带缓冲区和不带缓冲区的.不带缓冲区的频道,发送和接收是同步的,必须接收端接收了消息,发送端才能从发送调用中解脱.带缓冲区的频道,在缓冲区满之前,发送和接收是异步的,发送端的发送操作只保证把消息放入缓冲区. Go的频道是可以关闭的,关闭频道的目的是让接收端知道不会再有消息从这个频道进入,我们可能会用某个频道的关闭来表示某种状态的终结. 当我们关闭一个带缓冲区的频道时,如果缓冲区中还有消息,接收