Home GoLand 反射
Post
Cancel

GoLand 反射

Hello GoLand: https://blog.yexca.net/archives/154
GoLand (var and const) 变量与常量: https://blog.yexca.net/archives/155
GoLand (func) 函数: https://blog.yexca.net/archives/156
GoLand (slice and map) 切片: https://blog.yexca.net/archives/160
GoLand (OOP) 面向对象: https://blog.yexca.net/archives/162
GoLand (reflect) 反射: This Page

反射指一类应用,它们能够自描述和自控制

pair

Go 语言变量包括 type 和 value 部分,组成 pair

image

static type 是在编码时程序员看见的类型,concrete type 是在 runtime 系统看见的类型

类型断言能否成功,取决于变量的 concrete type,而不是 static type。因此一个 read 变量如果 concrete type 也实现了 write 方法的话,也可以被类型断言为 write

反射建立于类型之上,静态类型以及固定,因此反射主要与 interface 类型相关 (它是 concrete type)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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

1
2
3
4
5
6
7
8
9
10
11
12
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 变量

已知原数据类型

已知原数据类型可以直接强制转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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,如指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 获得

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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 赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 调用方法

通过函数名称调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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)

}

反射的基本原理

image

This post is licensed under CC BY 4.0 by the author.

东京科学大学大学院情报理工学院 2020 问题五 / 科学大院理工学 2020 問題五

-