核心概念
反射 (Reflection)
允许运行时动态查询和操作对象的类型和值
通过
reflect.TypeOf
和reflect.ValueOf
获取类型和值信息提供运行时动态获取类型和修改值的能力
灵活性高但性能较低
类型断言 (Type Assertion)
静态的类型转换机制
用于将
interface{}
转换为具体类型编译时检查类型安全性
要求开发者明确知道具体类型
反射操作
1. 获取类型和值信息
package main
import (
"fmt"
"reflect"
)
func main() {
var x int = 42
// 获取类型信息
t := reflect.TypeOf(x)
fmt.Println("类型:", t) // 类型: int
// 获取值信息
v := reflect.ValueOf(x)
fmt.Println("值:", v) // 值: 42
}
2. 修改变量的值
package main
import (
"fmt"
"reflect"
)
func main() {
var x int = 42
// 获取可寻址的反射值(通过指针)
v := reflect.ValueOf(&x)
// 修改变量值
v.Elem().SetInt(100)
fmt.Println("修改后的值:", x) // 修改后的值: 100
}
3. 调用方法(动态调用)
package main
import (
"fmt"
"reflect"
)
type Calculator struct{}
func (c Calculator) Add(a, b int) int {
return a + b
}
func main() {
calc := Calculator{}
// 获取方法
method := reflect.ValueOf(calc).MethodByName("Add")
// 准备参数
args := []reflect.Value{
reflect.ValueOf(10),
reflect.ValueOf(20),
}
// 调用方法并获取结果
result := method.Call(args)
fmt.Println("计算结果:", result[0].Int()) // 计算结果: 30
}
类型断言操作
基本使用
package main
import "fmt"
func main() {
var x interface{} = 42
// 安全类型断言
if v, ok := x.(int); ok {
fmt.Println("x是int类型:", v) // x是int类型: 42
} else {
fmt.Println("x不是int类型")
}
}
配合 switch 使用
package main
import "fmt"
func process(input interface{}) {
switch t := input.(type) {
case bool:
fmt.Printf("布尔值: %t\n", t)
case int:
fmt.Printf("整数: %d\n", t)
case string:
fmt.Printf("字符串: %s\n", t)
default:
fmt.Printf("未知类型: %T\n", t)
}
}
func main() {
process(true) // 布尔值: true
process(42) // 整数: 42
process("hello") // 字符串: hello
process(3.14) // 未知类型: float64
}
处理指针类型
package main
import "fmt"
func main() {
var num int = 42
var p interface{} = &num
// 指针类型断言
if ptr, ok := p.(*int); ok {
*ptr = 100
fmt.Println("修改后的值:", num) // 修改后的值: 100
}
}
反射与类型断言的比较
package main
import (
"fmt"
"reflect"
)
func main() {
var data interface{} = "Hello, Go!"
// 使用类型断言
if s, ok := data.(string); ok {
fmt.Println("使用类型断言获取值:", s)
} else {
fmt.Println("类型断言失败")
}
// 使用反射
v := reflect.ValueOf(data)
fmt.Println("使用反射获取类型:", v.Type()) // string
fmt.Println("使用反射获取值:", v.String()) // Hello, Go!
}
对比总结
最佳实践建议
优先选择类型断言
当明确知道具体类型时使用类型断言
性能更好,代码更安全
谨慎使用反射
仅在真正需要动态类型处理时使用
注意处理可能的panic
结合接口使用
使用接口定义清晰的行为
减少不必要的空接口使用
单元测试覆盖
反射代码需要全面测试
覆盖不同类型边界情况