1.Go语言的反射机制
再说明Go语言的反射机制之前,我们需要先了解Go语言的变量组成,Go语言的变量由两部分组成:
(1)数据类型(type)
Go语言中,数据类型又分为两种
- static type (int, strinng等基本类型)
- concrete type (由struct定义的类型,interface{}所指向的具体数据类型)
(2)数据的值(value)
1.1 pair
在GO语言中(数据类型+数据的值 = pair),这在在创建之后一直不变的。我们可以看个例子:
package main
import "fmt"
func main() {
// a的pair(type=string, value='hello')
var a string= "hello"
// b的pari(type=, value=)
var b interface{}
// b的pari(type=string, value='hello')
b = a
// b为什么可以断言成功?因此b的type是string
value, ok := b.(string)
fmt.Println(ok)
fmt.Println(value)
}
运行结果:
true
hello
可以看到,我们先声明了一个字符串变量a并赋值"hello",这时,a的pair就是(type=string, value='hello'),接着定义一个万能类型b,此时他的type和value均为0,我们让b=a,则b的pair(type=string, value='hello'),后面我们对string进行了一次类型转换(也可以理解类型断言),返回的是转换的结果ok,和转换后的类型value(string),这里需要注意的是,如果转换失败,返回的是该类型的零值。在这里,为什么类型转换能够成功呢,这就是pair在起作用,可以看到,interface{}变量b的pair的type为string,所以在对b做类型转换,转换成string时能够成功。
我们可以再举一个多态的例子:
package main
import "fmt"
type inter1 interface{
Walk()
}
type inter2 interface {
Run()
}
type interImpl struct {
}
func (this *interImpl) Walk(){
fmt.Println("Walk")
}
func (this *interImpl) Run(){
fmt.Println("Run")
}
func main() {
//a: pair(type=interImpl, value = interImpl{}的地址)
a := &interImpl{}
//b: pair(type=, value=)
var b inter1
//b: pair(type=interImpl, value = interImpl{}的地址)
b = a
b.Walk()
fmt.Println("..............................")
//c: pair(type=, value=)
var c inter2
//b: pair(type=interImpl, value = interImpl{}的地址)
c = b.(inter2)
c.Run()
}
运行结果:
Walk
..............................
Run
可以看到,我们定义两个接口inter1和inter2,interImpl是这个接口的实现类,我们再main方法中先声明interImpl类型的指针a并赋值,其pair(type=interImpl, value = interImpl{}的地址),接着,将其赋值给b,则b的pair就是(type=interImpl, value = interImpl{}的地址),紧接着,我们将b转换成inter2类型,可以看到是成功了的,为什么b可以转换成inter2类型呢,这就是pair不变性,即b本质上是interImpl类型(根据b 的pair的type),他一样实现了inter2接口,所以可以转换。
2.reflect包的简单用法
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Gender string
Age int
}
func (this *Person) Walk(){
fmt.Println("Walk")
}
func (this *Person) Run(){
fmt.Println("Run")
}
func main() {
// 声明一个Person类型并赋值
a := Person{"tom","female",15}
// 通过反射获取a变量的类型和值
aType := reflect.TypeOf(a)
aValue := reflect.ValueOf(a)
fmt.Println("a type is ", aType)
fmt.Println("a value is ", aValue)
}
运行结果:
a type is main.Person
a value is {tom female 15}
可以看到,通过reflect包的TypeOf方法和ValueOf方法可以很容易获取一个变量的类型和值,在这里a的数据类型为Person类型,其值为对象Person{"tom","female",15}。我们也可以通过reflect获取Person的属性值和方法:
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Gender string
Age int
}
func (this Person) Walk(){
fmt.Println("Walk")
}
func (this Person) Run(){
fmt.Println("Run")
}
func main() {
// 声明一个Person类型并赋值
a := Person{"tom","female",15}
// 通过反射获取a变量的类型和值
aType := reflect.TypeOf(a)
aValue := reflect.ValueOf(a)
for i := 0; i < aType.NumField(); i++ {
field := aType.Field(i)
value := aValue.Field(i).Interface()
fmt.Println(field.Name ," type is ", field.Type)
fmt.Println("value=", value)
}
for i := 0; i < aType.NumMethod(); i++ {
method := aType.Method(i)
methodValue := aValue.Method(i)
fmt.Println(method.Name, "type is", method.Type)
fmt.Println("value=", methodValue)
}
}
运行结果:
Name type is string
value= tom
Gender type is string
value= female
Age type is int
value= 15
Run type is func(main.Person)
value= 0x869040
Walk type is func(main.Person)
value= 0x869040
以上为reflect的简单应用,可以用TypeOf的返回值进一步获取属性和方法的类型
同理,可以用ValueOf的返回值进一步获取属性值和方法值。