开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:反射的快速入门(2)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9769
反射的快速入门(2)
内容介绍:
一、案例一
二、反射注意事项和细节说明
三、常量介绍
四、常量使用注意事项
一、案例一
请编写一个案例,演示对(结构体类型、interface{l}、reflect.value)进行反射的基本操作。
这节继续演示对结构体进行操作的案例
继续在原代码上添加:
在 fun reflectTest01(b interface{}){}
下输入
//专门演示反射[对结构体的反射]
fun reflectTest02(b interface{}){}
type Student struct {
//首先需要先声明一个结构体例 type
Name string
Age int
}
然后在 func main() {}中继续输入
//1.先定义一个 int
var num int = 100
ref1ectTest02(num)
//2.定义一个 Student 的实例
stu := Student{
Name : “tom”,
Age : 20,
}
之后进行的操作都可以在案例1的代码基础上修改,rTyp 的代码不需要改,之后删除掉
n2 := 2+ rVal.Int()
fmt.Println(“n2=”, n2)
后面的代码将 rVal 转成 interface{}接口的代码不变
下一步是将接口通过断言转成需要的类型,删除掉
num2 := iV.(int)
重新转成结构体,注释掉 fmt.Println(“num2=”,num2)
先来试着打印结果,直接输出 iV,观察它是什么类型,因为 rVal 本身就是由结构体反射过来,所以在输出时会发现如下现象:
先在 iV:= rVal.Interface() 下输入
fmt.Printf(“iV=%v iV=%T”, iV, iV)
试着运行结果,接着在 func main(){} 中继续输入 reflectTest01(stu),将 Student 传入。现在操作就是将学生这个结构体传给了
代码如下:
func ref1ectTesto2(b interface[){
//通过反射获取的传入的变量的 type , kind 值
//1.先获取到 reflect.Type
rTyp := reflect.Typeof(b)
fmt.Print1n( "rType=", rTyp)
//2.获取到 reflect.value
rval := reflect.valueof(b)
//下面我们将 rval 转成 interface{}iv := rva1.Interface()
fmt.Printf( "iv=%v iv type=%T\n", iV,iV)
//将 interface{} 通过断言转成需要的类型
}
写完之后我们来掉它,用 ref1ectTest02(stu)。然后将 var num int = 100 ref1ectTest02(num)注销。然后运行以下。我们发现它的类型是 main.Student。但是根本就把 Name 取不出来,也就是为什么将 interface{} 通过断言转成需要的类型。
fmt.Printf("iv=%v iv type=%T name=%v\n", iv, iv,iv.Name)
这样就会报错。我们要明确反射的本质是运行时的,在编译阶段是被有办法确定iV是什么,因此编译器在 iV.name 这里过不去。所以必须要将 interface{} 通过断言转成需要的类型。
我们这里可以用:
stu, ok := iv.(student)
这里,我们就简单使用了一带检测的类型断言。
同学们可以使用swtich的断言形式来做的更加的灵活。
然后我们进行判断,把整个字段取出来,代码如下:
if ok {
fmt.Printf("stu. Name=%v\n", stu.Name)
}
//这个时候就可以取到 name 了
这时候打印出的内容就是:
rType= main.Student
iv=iu t ype =main.Student
Stu.Name=tom
然后要进行获取变量对应的 Kind。
第一种方式:rVal.Kind()
Kind1 := rVal.Kind()
第二种方式:rTyp.Kind()
kind2 := rTyp.Kind()
fmt.PrintfC"kind =%v kind=%v\n", kind1,kind2)
输出的结果为:rType=main.Student
kind = struct kind = struct
iv =iv type=main.Student
Stu.Name=tom
我们可以看到两个 kind 都是 struct
二、反射注意事项和细节说明
1. reflect.Value.Kind 获取变量的类别,返回的是一个常量(看手册)
Kind 有两种方式可以拿到,第一种就是通过反射 Value 类型,这里面本身就提供了一种方法 Kind。Kind 返回v持有的值的分类,如果v是 Value 零值,返回值为Invalid。这里的 kind 就是个常量。
三、常量介绍
(一)常量使用 const 修改
(二)常量在定义的时候,必须初始化
(三)常量不能修改
(四)常量只能修饰 bool、数值类型(int,float系列)、string 类型,语法: const identifier [type] = value
我们举个例子:创建一个 main.go
package main
import ("fmt")
func main() {
var num int
const tax int
fmt.Print1n(num,tax)
}
此时会报错:没有一个表达式在后面,必须给他一个值所以要把 const tax int 变成const tax int = 0,所以常量在声明的时候必须赋值。
如果在 var num int 后面加一个 num = 90,这个是可以的,但是在 const tax int = 0 后面加一个 tax = 10,会报错:不能够辅助给 tax,所以常量是不能修改的。
举例说明,看看下面的写法是否正确:
const name = "tom" //ok
const tax float64 = 0.8 //ok
const a int //error没有进行初始化
const b = 9 / 3 //ok
会输出一个3,但是把9改成 num 就会报错,在编译的时候必须要确定b是多少 num 就不是常量,所以会报错。
const c = getVal() //error
四、常量使用注意事项
(一)比较简介的写法
func main() {
const (
a =1
b = 2
)
fmt.Print1n(a,b)
}
(二)还有一种专业的写法
func main() {
cont (
a = iota
b
c
)
fmt.Print1n(a,b,c)l/e,1,2
表示给a赋值为0,b在a的基础上+1,c在b的基础上+1,这种写法就比较专业了。
(三)Golang 中没有常量名必须字母大写的规范比如 TAX_RATE, 比如:
(四)仍然通过首字母的大小写来控制常量的访问范围