在 Golang 中,反射(reflection)用于在程序运行时获取程序的结构信息,并能动态调用程序的变量、函数和结构体。
反射主要通过 reflect 包实现,其中两个重要的类型是:
- reflect.Type: 表示类型的接口。我们可以通过 t.Name()获取类型名,t.Kind() 获取类型种类等。
- reflect.Value: 表示值的接口。我们可以通过 v.Int()获取 int 值,v.String()获取 string 值,v.CanAddr()判断是否可寻址等。
反射可以实现如下功能:
- 程序运行时获取变量的类型信息(类型名、种类等)。
- 调用程序运行时的变量、函数和结构体等。
- 修改程序运行时的变量的值。
- 根据字符串名称来获取变量的值。
例如:
func reflectType(x interface{}) {
typeOfX := reflect.TypeOf(x)
println(typeOfX.Name(), typeOfX.Kind())
}
func reflectValue(x interface{}) {
valueOfX := reflect.ValueOf(x)
println(valueOfX)
}
func reflectSetValue(x interface{}) {
valueOfX := reflect.ValueOf(x)
if valueOfX.Kind() == reflect.Int && valueOfX.CanSet() {
valueOfX.SetInt(100) //将x的值改为100
}
}
func reflectCallFunc(x interface{}) {
valueOfX := reflect.ValueOf(x)
params := []reflect.Value{reflect.ValueOf(10), reflect.ValueOf(20)}
result := valueOfX.Call(params)
println(result[0].Int())
}
func sum(x int, y int) int {
return x + y
}
func main() {
var x float64 = 3.4
reflectType(x) // float64 Float64
reflectValue(x) // 3.4
sum := sum // sum是一个函数
reflectCallFunc(sum) // 30
var y int = 10
reflectSetValue(y)
fmt.Println(y) // 100
}
反射的主要作用是在程序运行时动态获取信息和调用程序的变量、函数和结构体。这在其他语言中通常要借助于字符串的名字来实现,而 Go 语言的反射机制使这一点变的很容易。
反射虽然功能强大,但是也需要注意:
- 反射会降低程序的运行效率,所以不要滥用。
- 反射会破坏程序的抽象和封装性,可能导致一些意料之外的问题,所以要审慎使用。
- 通过反射设置的值不会触发其对应的方法,这可能带来一些副作用,需要注意。