反射机制 #
反射(Reflection)是Go语言的高级特性,允许程序在运行时检查类型信息、修改变量值、调用方法等。反射是很多框架和库的基础。
反射基础 #
reflect包 #
Go的反射功能由 reflect 包提供,核心类型是 reflect.Type 和 reflect.Value:
go
package main
import (
"fmt"
"reflect"
)
func main() {
x := 42
t := reflect.TypeOf(x)
v := reflect.ValueOf(x)
fmt.Println("类型:", t)
fmt.Println("值:", v)
fmt.Println("种类:", t.Kind())
}
Kind 种类 #
Kind 表示底层的具体类型:
go
package main
import (
"fmt"
"reflect"
)
func main() {
var (
b bool = true
i int = 42
f float64 = 3.14
s string = "hello"
sl []int = []int{1, 2, 3}
m map[string]int = map[string]int{"a": 1}
st struct{ X int } = struct{ X int }{10}
)
checkType(b)
checkType(i)
checkType(f)
checkType(s)
checkType(sl)
checkType(m)
checkType(st)
}
func checkType(x interface{}) {
t := reflect.TypeOf(x)
fmt.Printf("类型: %-10s 种类: %v\n", t.Name(), t.Kind())
}
常用Kind值:
| Kind | 说明 |
|---|---|
Bool |
布尔类型 |
Int, Int8, Int16, Int32, Int64 |
整数类型 |
Uint, Uint8, Uint16, Uint32, Uint64 |
无符号整数 |
Float32, Float64 |
浮点类型 |
String |
字符串 |
Array |
数组 |
Slice |
切片 |
Map |
映射 |
Struct |
结构体 |
Func |
函数 |
Interface |
接口 |
Ptr |
指针 |
获取和设置值 #
获取值 #
go
package main
import (
"fmt"
"reflect"
)
func main() {
x := 42
v := reflect.ValueOf(x)
fmt.Println("值:", v.Int())
fmt.Println("类型:", v.Type())
fmt.Println("能否获取Int:", v.CanInt())
}
设置值 #
要修改值,必须传递指针:
go
package main
import (
"fmt"
"reflect"
)
func main() {
x := 42
v := reflect.ValueOf(&x).Elem()
fmt.Println("修改前:", x)
if v.CanSet() {
v.SetInt(100)
}
fmt.Println("修改后:", x)
}
重要:
reflect.ValueOf传递的是值副本,要修改原值必须传递指针并使用Elem()获取指针指向的值。
结构体反射 #
获取字段信息 #
go
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string `json:"name" validate:"required"`
Age int `json:"age" validate:"min=0,max=150"`
City string `json:"city"`
}
func main() {
p := Person{
Name: "张三",
Age: 30,
City: "北京",
}
t := reflect.TypeOf(p)
v := reflect.ValueOf(p)
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
fmt.Printf("字段: %s\n", field.Name)
fmt.Printf(" 类型: %s\n", field.Type)
fmt.Printf(" 值: %v\n", value.Interface())
fmt.Printf(" 标签: %s\n", field.Tag.Get("json"))
fmt.Printf(" 验证: %s\n", field.Tag.Get("validate"))
fmt.Println()
}
}
修改结构体字段 #
go
package main
import (
"fmt"
"reflect"
)
type Config struct {
Host string
Port int
}
func main() {
config := Config{
Host: "localhost",
Port: 8080,
}
fmt.Println("修改前:", config)
v := reflect.ValueOf(&config).Elem()
hostField := v.FieldByName("Host")
if hostField.CanSet() {
hostField.SetString("127.0.0.1")
}
portField := v.FieldByName("Port")
if portField.CanSet() {
portField.SetInt(3000)
}
fmt.Println("修改后:", config)
}
遍历嵌套结构体 #
go
package main
import (
"fmt"
"reflect"
)
type Address struct {
City string
Country string
}
type User struct {
Name string
Age int
Address Address
}
func printStruct(v reflect.Value, indent string) {
t := v.Type()
for i := 0; i < v.NumField(); i++ {
field := t.Field(i)
fieldValue := v.Field(i)
fmt.Printf("%s%s: ", indent, field.Name)
if fieldValue.Kind() == reflect.Struct {
fmt.Println()
printStruct(fieldValue, indent+" ")
} else {
fmt.Println(fieldValue.Interface())
}
}
}
func main() {
user := User{
Name: "张三",
Age: 30,
Address: Address{
City: "北京",
Country: "中国",
},
}
printStruct(reflect.ValueOf(user), "")
}
方法反射 #
获取方法信息 #
go
package main
import (
"fmt"
"reflect"
)
type Calculator struct{}
func (c Calculator) Add(a, b int) int {
return a + b
}
func (c Calculator) Subtract(a, b int) int {
return a - b
}
func (c *Calculator) Multiply(a, b int) int {
return a * b
}
func main() {
c := Calculator{}
t := reflect.TypeOf(c)
fmt.Println("值接收者的方法:")
for i := 0; i < t.NumMethod(); i++ {
method := t.Method(i)
fmt.Printf(" %s: %v\n", method.Name, method.Type)
}
pt := reflect.TypeOf(&c)
fmt.Println("\n指针接收者的方法:")
for i := 0; i < pt.NumMethod(); i++ {
method := pt.Method(i)
fmt.Printf(" %s: %v\n", method.Name, method.Type)
}
}
动态调用方法 #
go
package main
import (
"fmt"
"reflect"
)
type Service struct {
Name string
}
func (s *Service) Hello(name string) string {
return fmt.Sprintf("Hello, %s! I'm %s.", name, s.Name)
}
func (s *Service) Add(a, b int) int {
return a + b
}
func callMethod(obj interface{}, methodName string, args ...interface{}) (interface{}, error) {
v := reflect.ValueOf(obj)
method := v.MethodByName(methodName)
if !method.IsValid() {
return nil, fmt.Errorf("method %s not found", methodName)
}
in := make([]reflect.Value, len(args))
for i, arg := range args {
in[i] = reflect.ValueOf(arg)
}
results := method.Call(in)
if len(results) == 0 {
return nil, nil
}
return results[0].Interface(), nil
}
func main() {
service := &Service{Name: "MyService"}
result, _ := callMethod(service, "Hello", "World")
fmt.Println(result)
result, _ = callMethod(service, "Add", 10, 20)
fmt.Println("10 + 20 =", result)
}
创建实例 #
使用反射创建值 #
go
package main
import (
"fmt"
"reflect"
)
func createInstance(t reflect.Type) (interface{}, error) {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("only struct types are supported")
}
v := reflect.New(t)
return v.Interface(), nil
}
func main() {
type Person struct {
Name string
Age int
}
pType := reflect.TypeOf(Person{})
instance, _ := createInstance(pType)
person := instance.(*Person)
person.Name = "张三"
person.Age = 30
fmt.Printf("%+v\n", person)
}
实用示例:简单的ORM映射 #
go
package main
import (
"fmt"
"reflect"
"strings"
)
type Model interface {
TableName() string
}
type User struct {
ID int `db:"id" pk:"true"`
Name string `db:"name"`
Age int `db:"age"`
}
func (u User) TableName() string {
return "users"
}
func getDBField(model interface{}) map[string]interface{} {
result := make(map[string]interface{})
v := reflect.ValueOf(model)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
dbTag := field.Tag.Get("db")
if dbTag != "" && dbTag != "-" {
result[dbTag] = v.Field(i).Interface()
}
}
return result
}
func buildInsert(model Model) string {
fields := getDBField(model)
var columns, placeholders []string
for col := range fields {
columns = append(columns, col)
placeholders = append(placeholders, "?")
}
return fmt.Sprintf(
"INSERT INTO %s (%s) VALUES (%s)",
model.TableName(),
strings.Join(columns, ", "),
strings.Join(placeholders, ", "),
)
}
func main() {
user := User{
ID: 1,
Name: "张三",
Age: 30,
}
fields := getDBField(user)
fmt.Println("字段映射:", fields)
sql := buildInsert(user)
fmt.Println("SQL:", sql)
}
实用示例:结构体复制 #
go
package main
import (
"fmt"
"reflect"
)
func CopyStruct(src, dst interface{}) error {
srcValue := reflect.ValueOf(src)
dstValue := reflect.ValueOf(dst)
if dstValue.Kind() != reflect.Ptr {
return fmt.Errorf("dst must be a pointer")
}
if srcValue.Kind() == reflect.Ptr {
srcValue = srcValue.Elem()
}
dstValue = dstValue.Elem()
srcType := srcValue.Type()
for i := 0; i < srcType.NumField(); i++ {
srcField := srcType.Field(i)
srcFieldValue := srcValue.Field(i)
dstFieldValue := dstValue.FieldByName(srcField.Name)
if dstFieldValue.IsValid() && dstFieldValue.CanSet() {
if dstFieldValue.Type() == srcFieldValue.Type() {
dstFieldValue.Set(srcFieldValue)
}
}
}
return nil
}
type Source struct {
Name string
Age int
Email string
}
type Destination struct {
Name string
Age int
City string
}
func main() {
src := Source{
Name: "张三",
Age: 30,
Email: "zhangsan@example.com",
}
var dst Destination
CopyStruct(src, &dst)
fmt.Printf("源: %+v\n", src)
fmt.Printf("目标: %+v\n", dst)
}
小结 #
| 函数/方法 | 说明 |
|---|---|
reflect.TypeOf() |
获取类型信息 |
reflect.ValueOf() |
获取值信息 |
Kind() |
获取底层类型种类 |
Elem() |
获取指针指向的元素 |
NumField() |
获取结构体字段数量 |
Field(i) |
获取第i个字段 |
FieldByName() |
按名称获取字段 |
NumMethod() |
获取方法数量 |
Method(i) |
获取第i个方法 |
Call() |
调用方法 |
反射是强大的工具,但也有代价:性能较低、类型安全性弱、代码可读性差。应该谨慎使用,优先考虑接口和代码生成等替代方案。