Golang 中的反射(reflection)是什么?如何使用?

在 Golang 中,反射(reflection)用于在程序运行时获取程序的结构信息,并能动态调用程序的变量、函数和结构体。

反射主要通过 reflect 包实现,其中两个重要的类型是:

  • reflect.Type: 表示类型的接口。我们可以通过 t.Name()获取类型名,t.Kind() 获取类型种类等。
  • reflect.Value: 表示值的接口。我们可以通过 v.Int()获取 int 值,v.String()获取 string 值,v.CanAddr()判断是否可寻址等。

反射可以实现如下功能:

  1. 程序运行时获取变量的类型信息(类型名、种类等)。
  2. 调用程序运行时的变量、函数和结构体等。
  3. 修改程序运行时的变量的值。
  4. 根据字符串名称来获取变量的值。

例如:

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 语言的反射机制使这一点变的很容易。

反射虽然功能强大,但是也需要注意:

  1. 反射会降低程序的运行效率,所以不要滥用。
  2. 反射会破坏程序的抽象和封装性,可能导致一些意料之外的问题,所以要审慎使用。
  3. 通过反射设置的值不会触发其对应的方法,这可能带来一些副作用,需要注意。