Golang的Reflect包是做什么用的?
Reflection in computing is the ability of a program to examine its own structure, particularly through types;it’s a form of metaprogramming
反射是程序检查其自身结构的能力,尤其是通过类型;它是元编程的一种形式。
From The Go Blog - The Laws of Reflection
上面是反射的定义,也就是golang Reflect包设计的目的。
元编程是什么?
元编程是一种编程技术,其中计算机程序具有将其他程序视为其数据的能力。这意味着可以设计一个程序来读取,生成,分析或转换其他程序,甚至在运行时对其进行修改。在某些情况下,这使程序员可以最大程度地减少表达解决方案的代码行数,从而减少开发时间。它还使程序具有更大的灵活性,可以有效地处理新情况而无需重新编译。
From: wiki - Metaprogramming
interface
在Golng中,interface和reflection是互相依赖的特性,了解什么事反射前,需要了解好interface。
io.Readerio.Wirter
// Reader is the interface that wraps the basic Read method.
type Reader interface {
Read(p []byte) (n int, err error)
}
// Writer is the interface that wraps the basic Write method.
type Writer interface {
Write(p []byte) (n int, err error)
}
ReadReadfunc Printer(r io.Reader) {}
interface{}
现在就可以一起看看golang中的反射机制了
Reflect.TypeOf和Reflect.ValueOf
key-valuereflect.Typereflet.Value
下面针对golang已有的变量类型去看看如何通过reflect去操作变量的例子。
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
// =================
// type: float64
var x float64 = 3.4
fmt.Println("value:", reflect.ValueOf(x).String())
// =================
// value: <float64 Value>
}
reflect.Typereflect.Value
var x uint8 = 'x'
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type()) // uint8.
fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true.
x = uint8(v.Uint()) // v.Uint returns a uint64.
reflect.ValueInterface()refect.Valueinterface
y := v.Interface().(float64) // y will have type float64.
fmt.Println(y)
使用反射操作变量
reflect.ValueCanSet()
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("settability of v:", v.CanSet())
// ==============
// settability of v: false
变量v变量x变量x
而正确的方式应该是,先取变量地址的值,然后通过指针获取变量的值。
var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: 取x的地址.
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())
// ================
// type of p: *float64
// settability of p: false
v := p.Elem() // Note: 取地址指向的具体值
fmt.Println("settability of v:", v.CanSet())
// ==============
settability of v: true
使用reflect操作struct
上面说了这么多,现在我们再回到主题,这才是这边文章想要说的东西。
interface{}struct
上面的简单例子,是用反射修改变量的值,如果变量类型是struct,其实同样可以也是修改struct field的值的
reflect.Value
type T struct {
A int
B string
}
t := T{23, "skidoo"}
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())
}
// ===================
// 0: A int = 23
// 1: B string = skidoo
TagsTags
而修改struct字段,可以
s.Field(0).SetInt(77)
s.Field(1).SetString("Sunset Strip")
fmt.Println("t is now", t)
// ===============
// t is now {77 Sunset Strip}