Golang Series
Hello GoLang: https://blog.yexca.net/archives/154
GoLang (var and const) 变量与常量: https://blog.yexca.net/archives/155
GoLang (func) 函数: https://blog.yexca.net/archives/156
GoLang (slice and map) 切片: https://blog.yexca.net/archives/160
GoLang (OOP) 面向对象: https://blog.yexca.net/archives/162
GoLang (reflect) 反射: This Page
GoLang (struct tag) 结构体标签: https://blog.yexca.net/archives/205
GoLang (goroutine) go 程: https://blog.yexca.net/archives/206
GoLang (channel) 通道: https://blog.yexca.net/archives/207
反射指一类应用,它们能够自描述和自控制
pair
Go 语言变量包括 type 和 value 部分,组成 pair
static type 是在编码时程序员看见的类型,concrete type 是在 runtime 系统看见的类型
类型断言能否成功,取决于变量的 concrete type,而不是 static type。因此一个 read 变量如果 concrete type 也实现了 write 方法的话,也可以被类型断言为 write
反射建立于类型之上,静态类型以及固定,因此反射主要与 interface 类型相关 (它是 concrete type)
package main
import "fmt"
type ReadBook interface {
Read()
}
type WriteBook interface {
Write()
}
type Book struct {
}
func (this *Book) Read() {
fmt.Println("read Book")
}
func (this *Book) Write() {
fmt.Println("write Book")
}
func main() {
// b: pair<type:Book, value:book{}地址>
b := &Book{}
// r: pair<type:, value:>
var r ReadBook
// r: pair<type:Book, value:book{}地址>
r = b
r.Read()
var w WriteBook
w = r.(WriteBook) // 因为r的type是Book,所以
w.Write()
}
TypeOf and ValueOf
reflect.TypeOf() 是获取 pair 中的 type,reflect.ValueOf() 获取 pair 中的 value
package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a)) // float64
fmt.Println("value of a:", reflect.ValueOf(a)) // 3.14
}
类型转换
执行 reflect.ValueOf() 后得到类型为 reflect.Value 变量
已知原数据类型
已知原数据类型可以直接强制转换
package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a))
fmt.Println("value of a:", reflect.ValueOf(a))
value := reflect.ValueOf(a)
fmt.Printf("type of value:%T\n", value) // reflect.Value
newA := value.Interface().(float64)
fmt.Printf("type of newA:%T\n", newA) // float64
}
需要注意类型转换需要完全一致,否则将会 panic,如指针
package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
fmt.Println("type of a:", reflect.TypeOf(a))
fmt.Println("value of a:", reflect.ValueOf(a))
// 传输地址
point := reflect.ValueOf(&a)
fmt.Printf("type of value:%T\n", point) // reflect.Value
// 转换类型为指针
newA := point.Interface().(*float64)
fmt.Printf("type of newA:%T\n", newA) // *float64
}
也就是说反射可以将 “反射类型对象” 再重新转换为 “接口类型变量”
未知原数据类型
通过遍历探寻 Field 获得
package main
import (
"fmt"
"reflect"
)
type Person struct {
// 一行为一个 field
Name string
Age int
Rank float64
}
// 注意方法为公有,若私有则无法访问
func (person Person) Sleep() {
fmt.Println("person sleep")
}
func main() {
p := Person{"zhangSan", 18, 5.2}
getFieldAndMethod(p)
}
func getFieldAndMethod(input interface{}) {
getType := reflect.TypeOf(input)
fmt.Println("type:", getType.Name())
getValue := reflect.ValueOf(input)
fmt.Println("value/AllField:", getValue)
// 获取属性
numField := getValue.NumField()
for i := 0; i < numField; i++ {
fieldType := getType.Field(i)
fieldValue := getValue.Field(i).Interface()
fmt.Printf("%s: %v = %v\n", fieldType.Name, fieldType.Type, fieldValue)
}
// 获取方法
numMethod := getType.NumMethod()
for i := 0; i < numMethod; i++ {
method := getType.Method(i)
fmt.Printf("%s: %v\n", method.Name, method.Type)
}
}
通过 reflec.Value 赋值
package main
import (
"fmt"
"reflect"
)
func main() {
a := 3.14
// 只有是指针时才可赋值
pointer := reflect.ValueOf(&a)
// 设置指向该地址,获取原始值
newValue := pointer.Elem()
// 判断是否可以设置值
fmt.Println("value canSet:", newValue.CanSet())
if newValue.CanSet() {
// 如果可以设置
newValue.SetFloat(9.96)
// 显示变量值
fmt.Println("value of a:", a) // 9.96
} else {
fmt.Println("error")
}
}
通过 reflec.Value 调用方法
通过函数名称调用
package main
import (
"fmt"
"reflect"
)
type User struct {
name string
age int
}
func (user User) MethodHasArgs(a string, b int) {
fmt.Println("User MethodHasArgs")
}
func (user User) MethonNotArgs() {
fmt.Println("User MethodNotArgs")
}
func main() {
user := User{"zhangSan", 18}
value := reflect.ValueOf(user)
// 通过函数名调用
method1 := value.MethodByName("MethodHasArgs")
// 构建参数
args1 := []reflect.Value{reflect.ValueOf("string"), reflect.ValueOf(18)}
// 调用函数
method1.Call(args1)
// 无参调用
method2 := value.MethodByName("MethonNotArgs")
args2 := make([]reflect.Value, 0)
method2.Call(args2)
}