反射是一种在运行时操作不同类型对象的能力,它可以让程序动态地获取和修改对象的类型、值、方法等信息。
Go 语言中提供了 reflect 包来支持反射功能,它包含了两个重要的类型:reflect.Type 和 reflect.Value,以及两个重要的函数:reflect.TypeOf 和 reflect.ValueOf。
reflect.Type 表示一个对象的类型信息,它包含了对象的名称、大小、对齐方式、方法集等元数据。
reflect.Value 表示一个对象的值信息,它包含了对象的具体数据和类型指针。
reflect.TypeOf 函数接受一个 interface{} 类型的参数,返回该参数对应的 reflect.Type 类型。
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
}
func main() {
p := Person{"Alice", 20}
t := reflect.TypeOf(p)
fmt.Println(t.Name()) // Person
fmt.Println(t.Kind()) // struct
}
reflect.ValueOf 函数接受一个 interface{} 类型的参数,返回该参数对应的 reflect.Value 类型。通过 reflect.Type 和 reflect.Value 类型,我们可以获取和修改对象的各种属性和行为。
package main
import (
"fmt"
"reflect"
)
type test struct {
a int64
b string
c []uint8
}
func (t *test) SetIndexedField(index int, value interface{}) error {
v := reflect.ValueOf(t).Elem()
field := v.Field(index)
if !field.CanSet() {
return fmt.Errorf("Cannot set field %d", index)
}
fieldType := field.Type()
val := reflect.ValueOf(value)
if val.Type().ConvertibleTo(fieldType) {
val = val.Convert(fieldType)
} else {
return fmt.Errorf("Cannot convert %v to %v", val.Type(), fieldType)
}
field.Set(val)
return nil
}
func main() {
var t = test{10, "test string", []uint8{1, 2, 3, 4}}
fmt.Println(t) // {10 test string [1 2 3 4]}
t.SetIndexedField(0, 5) // set a to 5
t.SetIndexedField(1, "new string") // set b to "new string"
t.SetIndexedField(2, []uint8{8, 9}) // set c to []uint8{8,9}
fmt.Println(t) // {5 new string [8 9]}
}
使用 Kind 方法判断对象属于哪种基础类型(如 int, string, slice 等)。
package main
import (
"fmt"
"reflect"
)
func main() {
var x int = 100
var y string = "hello"
var z []int = []int{1, 2, 3}
fmt.Println(reflect.TypeOf(x).Kind()) // int
fmt.Println(reflect.TypeOf(y).Kind()) // string
fmt.Println(reflect.TypeOf(z).Kind()) // slice
}
使用 NumField 和 Field 方法遍历结构体中的字段。
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
}
func main() {
p := Person{"Alice", 20}
t := reflect.TypeOf(p)
v := reflect.ValueOf(p)
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
fmt.Printf("field name: %s\n", f.Name)
fmt.Printf("field type: %s\n", f.Type)
fmt.Printf("field value: %v\n", v.Field(i))
}
}
使用 NumMethod 和 Method 方法调用对象上的方法。
package main
import (
"fmt"
"reflect"
)
type Animal struct {
Name string
}
func (a Animal) Speak() {
fmt.Printf("%s says hello\n", a.Name)
}
func (a Animal) Eat(food string) {
fmt.Printf("%s eats %s\n", a.Name, food)
}
func main() {
a := Animal{"Dog"}
t := reflect.TypeOf(a)
v := reflect.ValueOf(a)
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
fmt.Printf("method name: %s\n", m.Name)
v.Method(i).Call(nil) // call method without arguments
}
args := []reflect.Value{reflect.ValueOf("bone")}
v.MethodByName("Eat").Call(args) // call method with arguments
}
使用 Elem 方法获取指针或者接口指向的元素。
package main
import (
"fmt"
"reflect"
)
type Shape interface {
Draw()
}
type Circle struct {
R float64
}
func (c Circle) Draw() {
fmt.Printf("draw a circle with radius %.2f\n", c.R)
}
func main() {
var s Shape = Circle{10.0}
t1 := reflect.TypeOf(s) // interface type
t2 := reflect.TypeOf(&s) // pointer type
e1 := t1.Elem() // concrete type (Circle)
e2 := t2.Elem().Elem() // concrete type (Circle)
fmt.Println(t1, e1) // Shape Circle
fmt.Println(t2, e2) // *Shape Circle
v1 := reflect.ValueOf(s) // interface value
v2 := reflect.ValueOf(&s) // pointer value
e3 := v1.Elem() // concrete value (Circle{10})
e4 := v2.Elem().Elem() // concrete value (Circle{10})
fmt.Println(v1, e3) // <Circle Value> {10}
fmt.Println(v2, e4) // <*Shape Value> {10}
}
使用 CanSet 方法判断对象是否可寻址和可修改。
package main
import (
"fmt"
"reflect"
)
func main() {
x := 100 // x is not addressable and not settable
y := &x // y is addressable but not settable
z := reflect.ValueOf(&x).Elem() // z is addressable and settable
vx:= reflect.ValueOf(x)
vy:= reflect.ValueOf(y)
vz:= z
fmt.Println(vx.CanSet()) // false
fmt.Println(vy.CanSet()) // false
fmt.Println(vz.CanSet()) // true
}
使用 reflect.New 方法创建指定类型的对象。
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
}
func main() {
t := reflect.TypeOf(Person{})
v := reflect.New(t) // create a pointer to Person
fmt.Println(v.Type()) // *Person
fmt.Println(v.Kind()) // ptr
fmt.Println(v.Elem().Type()) // Person
fmt.Println(v.Elem().Kind()) // struct
p := v.Interface().(*Person) // convert to Person pointer
p.Name = "Bob"
p.Age = 30
fmt.Println(p) // &{Bob 30}
}
使用 reflect.MakeSlice 和 reflect.Append 方法创建和扩展切片。
package main
import (
"fmt"
"reflect"
)
func main() {
t := reflect.TypeOf([]int{}) // slice type
v := reflect.MakeSlice(t, 0, 10) // create a slice with len=0 and cap=10
fmt.Println(v.Len(), v.Cap()) // 0 10
v = reflect.Append(v, reflect.ValueOf(1)) // append an element
v = reflect.AppendSlice(v, reflect.ValueOf([]int{2, 3})) // append another slice
s := v.Interface().([]int) // convert to []int
fmt.Println(s) // [1 2 3]
}
使用 reflect.MakeMap 和 reflect.SetMapIndex 方法创建和修改映射。
package main
import (
"fmt"
"reflect"
)
func main() {
t := reflect.TypeOf(map[string]int{}) // map type
v := reflect.MakeMap(t) // create a map
k1 := reflect.ValueOf("one") // key value
v1 := reflect.ValueOf(1) // value value
k2 := reflect.ValueOf("two") // key value
v2 := reflect.ValueOf(2) // value value
v.SetMapIndex(k1, v1) // set map["one"] = 1
v.SetMapIndex(k2, v2) // set map["two"] = 2
m := v.Interface().(map[string]int)
使用 reflect.StructTag 方法获取结构体字段上的标签。
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
t := reflect.TypeOf(Person{})
f1 := t.Field(0) // get the first field
f2 := t.Field(1) // get the second field
fmt.Println(f1.Tag.Get("json")) // name
fmt.Println(f2.Tag.Get("json")) // age
}
使用 reflect.MakeFunc 方法创建一个函数对象。
package main
import (
"fmt"
"reflect"
)
func main() {
t := reflect.FuncOf([]reflect.Type{reflect.TypeOf(0)}, []reflect.Type{reflect.TypeOf("")}, false) // create a function type of func(int) string
v := reflect.MakeFunc(t, func(args []reflect.Value) []reflect.Value { // create a function value of that type
n := args[0].Int() // get the first argument as int
s := fmt.Sprintf("%d", n) // convert it to string
return []reflect.Value{reflect.ValueOf(s)} // return a slice of values containing s
})
f := v.Interface().(func(int) string) // convert to func(int) string
fmt.Println(f(100)) // 100
}
使用 reflect.DeepEqual 方法比较两个对象是否相等。
package main
import (
"fmt"
"reflect"
)
type person struct {
name string
age int
}
func main() {
p1 := person{"Alice", 20}
p2 := person{"Alice", 20}
p3 := person{"Bob", 25}
fmt.Println(reflect.DeepEqual(p1, p2)) // true
fmt.Println(reflect.DeepEqual(p1, p3)) // false
}