nil不一定等于空接口,因为一个 interface 底层 由 type + value 构成,只有 type 和 value 都匹配,才能 ==reflect.VlaueOf 就是用来获取具体的 reflect.Valuereflect.TypeOf 用来获取具体的 reflect.Typefunc main() {
var (
a *A
b interface{}
)
fmt.Println(a)
if b == nil {
fmt.Println("b is nil")
}
fmt.Println(reflect.TypeOf(b), reflect.ValueOf(b))
fmt.Println(reflect.TypeOf(a), reflect.ValueOf(a))
b = a
if b == nil {
fmt.Println("b is nil")
} else {
fmt.Printf("current b is %v \n", b)
fmt.Println("b not eq nil")
}
fmt.Println(reflect.TypeOf(b), reflect.ValueOf(b))
}

上面的代码说明了,刚开始的空接口 == nil,后来的接口为啥不等于 nil,因为 type变了,虽然value 还是 nil
reflect.Value 或者 reflect.Type 的 NumField 获取属性数量reflect.Type 的 Field 方法 获取属性相关信息reflect.Value 的 Field 方法 获取值相关信息package main
import (
"fmt"
"reflect"
)
type A struct {
Name string
Age int
}
func main() {
var a A
getType := reflect.TypeOf(a)
getValue := reflect.ValueOf(a)
fmt.Println("field num", getType.NumField())
for i := 0; i < getType.NumField(); i++ {
field := getType.Field(i)
value := getValue.Field(i)
fmt.Println("field name is", field.Name, "field value is", value.Interface())
}
}

reflect.ValueOf 传入的必须是指针类型,只有原始反射对象可以进行修改,可以通过 reflect.Value 的 Elem 方法取得reflect.Value 的 Canset 方法来判断是否可以设置Set... 系列方法来设置具体类型的值package main
import (
"fmt"
"reflect"
)
type A struct {
Name string
Age int
}
func main() {
a := A{
Name: "old name",
}
valueOfA := reflect.ValueOf(&a).Elem()
nameField := valueOfA.Field(0)
if nameField.CanSet() {
nameField.SetString("new name")
} else {
fmt.Println("don't set")
}
fmt.Println("new value", a.Name)
}
set... 设置值,需要知道类型,可以通过 reflect.Type 的 kind 方法获取原始类型
set... 方法package main
import (
"fmt"
"reflect"
)
type A struct {
Name string
Age int
}
func main() {
a := A{
Name: "old name",
}
fmt.Println("old value", a.Name)
valueOfA := reflect.ValueOf(&a).Elem()
getType := reflect.TypeOf(a)
field := getType.Field(0)
nameField := valueOfA.Field(0)
if nameField.CanSet() {
switch field.Type.Kind() {
case reflect.String:
fmt.Println("string")
nameField.SetString("new value")
}
} else {
fmt.Println("don't set")
}
fmt.Println("new value", a.Name)
}

reflect.Type 的 NumMethod 方法获取方法数量reflect.Type 的 Method 方法获取到具体的方法信息 reflect.Methodpackage main
import (
"fmt"
"reflect"
)
type A struct {
Name string
Age int
}
func (receiver *A) SetName(name string) {
receiver.Name = name
}
func (receiver *A) SetAge(age int) {
receiver.Age = age
}
func main() {
var a A
//有方法是依赖指针的所以需要传指针
getType := reflect.TypeOf(&a)
num := getType.NumMethod()
for i := 0; i < num; i++ {
method := getType.Method(i)
fmt.Println("method name:", method.Name, "method type:", method.Type)
}
}

reflect.Method 的 Call 方法即可调用反射对象的方法
reflect.Value 的切片reflect.Value 的空切片即可reflect.Value 组成切片,传入 Call 完成调用package main
import (
"fmt"
"reflect"
)
type A struct {
Name string
Age int
}
type Body struct {
Like string
Desc string
}
func (a A) Pr() {
fmt.Println("A pr")
}
func (a A) Talk(b Body) {
fmt.Printf("Like:%s,Desc:%s", b.Like, b.Desc)
}
func main() {
var a A
getType := reflect.ValueOf(a)
pr := getType.Method(0)
//不需要参数
pr.Call([]reflect.Value{})
b := Body{
Like: "i'm like",
Desc: "i'm desc",
}
talk := getType.Method(1)
//Talk 需要传入 Body struct, 所以反射调用,需要传入 由 Body的 reflect.Value 组成切片参数
talk.Call([]reflect.Value{
reflect.ValueOf(b),
})
}

reflect.kind 大量的枚举 + 类型转换 等操作reflect.Value 不能复用,每次都是返回一个新的值,其中 typ 还是指针类型,涉及对指针的频繁分配,GC

