go

go 反射

go 是静态类型语言。注意,interface 也是静态类型,如果一个接口变量被赋值了其他变量,那么其他变量必须实现该接口包含的方法。

type MyInt int
var a MyInt
// a 的静态类型是 MyInt,底层类型是 int。
// 获取静态类型:reflect.TypeOf(a)
// 获取底层类型:relect.TypeOf(a).Kind() 或 relect.ValueOf(a).Kind()
  1. reflect.TypeOf(i) :获得接口值的类型
  2. reflect.ValueOf(i):获得接口值的值

这两个方法返回的对象,我们称之为反射对象:Type object 和 Value object。

反射第一定律:反射可以将接口类型变量转换为反射类型变量。

func main() {
    var age interface{} = 25

    fmt.Printf("原始接口变量的类型为 %T,值为 %v \n", age, age)

    t := reflect.TypeOf(age)
    v := reflect.ValueOf(age)

    // 从接口变量到反射对象
    fmt.Printf("从接口变量到反射对象:Type对象的类型为 %T \n", t)
    fmt.Printf("从接口变量到反射对象:Value对象的类型为 %T \n", v)
}
//原始接口变量的类型为 int,值为 25
//从接口变量到反射对象:Type对象的类型为 *reflect.rtype
//从接口变量到反射对象:Value对象的类型为 reflect.Value

反射第二定律:反射可以将反射类型变量转换成接口类型变量。

func main() {
    var age interface{} = 25

    fmt.Printf("原始接口变量的类型为 %T,值为 %v \n", age, age)

    t := reflect.TypeOf(age)
    v := reflect.ValueOf(age)

    // 从接口变量到反射对象
    fmt.Printf("从接口变量到反射对象:Type对象的类型为 %T \n", t)
    fmt.Printf("从接口变量到反射对象:Value对象的类型为 %T \n", v)

    // 从反射对象到接口变量
    i := v.Interface()
    fmt.Printf("从反射对象到接口变量:新对象的类型为 %T 值为 %v \n", i, i)
}
//原始接口变量的类型为 int,值为 25
//从接口变量到反射对象:Type对象的类型为 *reflect.rtype
//从接口变量到反射对象:Value对象的类型为 reflect.Value
//从反射对象到接口变量:新对象的类型为 int 值为 25

反射第三定律:如果要修改”反射类型变量“,其值必须是”可写的“(setable)。

package main

import (
    "fmt"
    "reflect"
)

func main() {
    var x float32 = 1.1

    v := reflect.ValueOf(x)
    //v.SetFloat(1.2)        // panic
    fmt.Println(v.CanSet())  // false

    v = reflect.ValueOf(&x)
    fmt.Println(v.CanSet())  // false 因为我们要改的是 *v

    target := v.Elem()
    fmt.Println(target.CanSet())

    target.SetFloat(2.3)
    fmt.Println(x)           // 2.3
}

发表评论