Go语言学习之入门篇(十三)

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的返回值进一步获取属性值和方法值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值