【Golang学习】第十一章 断言Assertion和反射reflection

目录

一、断言Assertion

1. 使用

2. 检测

二、反射reflection

1. 什么是反射

2. 为什么要用反射

3. 反射的用法和主要函数


一、断言Assertion

1. 使用

        接口是一般类型,不知道具体类型,断言就是把一个接口类型指定为它原始的类型。

type User struct {
	Name string
	Age	int
	Sex	bool
}
func (u User)SayName(name string) {
	fmt.Println("My name is", name)
}

type Student struct {
	Class string
	User
}

func main(){
	u := User{
		Name: "Entin",
		Age:  18,
		Sex:  true,
	}
	s := Student{"三年A班", u}
	check1(u)
	check2(s)
}

func check1(i interface{}) {
	// 把一个接口类型断言为它的原始结构,
	// 并且可以调用原始结构的属性和方法
	i.(User).SayName(i.(User).Name)
}

func check2(i interface{}) {
	// i.(type) 可以获取当前传入的i的类型
	switch i.(type) {
	case User:
		fmt.Println("I'm User.")
		fmt.Println(i.(User).Name)
	case Student:
		fmt.Println("I'm Student.")
		fmt.Println(i.(Student).Class)
	}
}

/*
输出结果:
My name is Entin
I'm Student.
三年A班
*/

2. 检测

        在进行类型断言时,如果类型不匹配,就会产生 panic ,此时可以带上检测机制,即使类型不匹配也不产生 panic 。

// 类型断言(带检测机制)
var x interface{}
var i int = 7
x = i	// x是空接口,可以接收任何类型
// 断言成功
if y, ok := x.(int); ok {
	fmt.Printf("success, y = %d\n", y)
} else {
	fmt.Println("fail")
}
// 断言失败
if z, ok := x.(string); ok {
	fmt.Printf("success, z= %s\n", z)
} else {
	fmt.Println("fail")
}

/*
输出结果:
success, y = 7
fail
*/

二、反射reflection

1. 什么是反射

        官方说法:在编译时不知道类型的情况下,可更新变量、运行时查看值调用方法以及直接对他们的布局进行操作的机制,称为反射。

        通俗说法:可以知道本数据的原始数据类型、原始数据内容和原始方法等,并且可以对原始数据进行一定的操作。

2. 为什么要用反射

        我们通过接口或者其它方式接收到类型不固定的数据时,需要写太多的 switch case 断言代码,此时代码不灵活且通用性差,使用反射可以无视数据类型,直接改变原数据结构中的数据。

3. 反射的用法和主要函数

type User struct {
	Name string
	Age	int
	Sex	bool
}
func (u User)SayName(name string) {
	fmt.Println("My name is", name)
}

type Student struct {
	Class string
	User
}

func main(){
	u := User{
		Name: "Entin",
		Age:  18,
		Sex:  true,
	}
	s := Student{"三年A班", u}
	check3(s)
	check4(&s)
	fmt.Println(s)	// {三年A班 {Entin 19 true}}
}

func check3(i interface{}) {
	t := reflect.TypeOf(i)	// 获取输入参数接口中的值的类型
	v := reflect.ValueOf(i)	// 获取输入参数接口中的数据的值
	fmt.Println(t, v)	// main.Student {三年A班 {Entin 18 true}}
	// 获取t的值的个数
	fmt.Println(t.NumField())	// 2
	// 按下标获取v的值
	fmt.Println(v.Field(0))	// 三年A班
	// 按层级取值
	fmt.Println(v.FieldByIndex([]int{0}))	// 三年A班
	fmt.Println(v.FieldByIndex([]int{1}))	// {Entin 18 true}
	fmt.Println(v.FieldByIndex([]int{1, 0}))	// Entin
	// 按属性名取值
	fmt.Println(v.FieldByName("Age"))	// 18
	// 判断类型
	fmt.Println(t.Kind())	// struct
	// 通过反射调用方法
	f := v.Method(0)
	f.Call([]reflect.Value{reflect.ValueOf("Nanase")})	// My name is Nanase
}

func check4(i interface{}) {
	v := reflect.ValueOf(i)
	e := v.Elem()	// 获取原始数据并操作
	e.FieldByName("Age").SetInt(19)	// 改变原始数据的值
	fmt.Println(i)	// &{三年A班 {Entin 19 true}}
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值