目录
一、断言Assertion1. 使用
接口是一般类型,不知道具体类型,断言就是把一个接口类型指定为它原始的类型。
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}}
}