曲靖网站制作,备案网站分布地点,做系统去哪网站下载镜像,wordpress积分商城主题Golang面向API编程-interface#xff08;接口#xff09; 作者#xff1a;尹正杰 版权声明#xff1a;原创作品#xff0c;谢绝转载#xff01;否则将追究法律责任。 Golang并不是一种典型的面向对象编程#xff08;Object Oriented Programming#xff0c;OOP#xf… Golang面向API编程-interface接口 作者尹正杰 版权声明原创作品谢绝转载否则将追究法律责任。 Golang并不是一种典型的面向对象编程Object Oriented ProgrammingOOP面向对象程序设计语言。它在语法上不支持类和继承的概念。没有继承是否就无法拥有多态行为了呢答案是否定的我们知道 Golang 中没有 class 的概念而是通过 interface 类型转换支持在动态类型语言中常见的“鸭子类型”达到运行时多态的效果。 一.什么是interface 简单的说interface是一组method的组合我们通过interface来定义对象的一组行为。换句话说一个 interface 类型定义了一个“方法集合”作为其接口。 interface类型的变量可以保存含有属于这个interface类型的任何类型的值这时我们就说这个类型实现了这个接口。未被初始化的interface类型变量的零值为空nil。 二.interface类型和值 接口类型实际上是一组method方法签名的清单。interface 类型定义了一组方法如果某个对象实现了某个接口的所有方法则此对象就实现了此接口。接口也是一种数据类型。如果你声明了一个接口变量这个变量能够存储任何实现该接口的对象类型。最后任意的类型都实现了空interface(我们这样定义interface{})也就是包含 0 个method的interface。所以我喜欢给它起一个绰号叫“大胃王”。 定义一个interface以及调用方式如下 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import (
11 fmt
12 strings
13 )
14
15 type Human struct {
16 Name string //定义姓名
17 string //内置的匿名字段我们用它来定义家庭住址。
18 phone int //电话号码
19 }
20
21 type Student struct {
22 Human //匿名字段其类型就是我们上面自定义的类型。
23 Classroom string //教室名称
24 Score float64 //考试成绩
25 }
26
27 type Teacher struct {
28 Human //匿名字段
29 Position string //职位信息
30 salary float64 //薪资情况
31 }
32
33
34 func (h Human) SayHi() { //定义结构体“Human”自我介绍的方法。
35 fmt.Printf(Hello, my name is 【%s】. My phone number is【%d】.My home address is【%s】\n, h.Name,
36 h.phone,h.string) //格式化输出是可以换行的哟。
37 }
38
39
40 func (h Human) Sing(Name string) { //定义结构体“Human”唱歌的方法
41 fmt.Printf(【%s】我有一只小毛驴我从来也不骑有一天我心血来潮骑它去赶集.....\n, Name)
42 }
43
44
45 func (t Teacher) SayHi() { //定义结构体“Teacher”自我介绍的方法。
46 fmt.Printf(Anyway, Im your 【%s】 teacher, you can call me 【%s】,My salary is...【%f】\n, t.Position,
47 t.Human.Name,t.salary)
48 }
49
50
51 type Superman interface { //定义一个接口
52 SayHi() //这个接口包含“SayHi() ”方法。
53 Sing(Name string) //该接口也包含“Sing(Name string)”方法。
54 }
55
56 func main() {
57 yzj : Student{Human{尹正杰, 北京, 7474741}, 三年级一班, 95} //初始化我们定义的结构体。我们也可以将这个过程叫做实例化。而将“yzj”叫做实例。
58 hsy : Student{Human{韩森雨, 北京, 2424241}, 一年级五班, 100}
59 bingan : Teacher{Human{饼干, 北京, 6464641}, Golang, 30000}
60
61
62 var yinzhengjie Superman //声明一个变量其类型为我们定义的接口。
63
64 yinzhengjie yzj //注意了这是接受了我们定义第一个类型。
65 yinzhengjie.SayHi() //并且可以调用这个类型下的“SayHi()”方法已经“Sing(高音唱)”方法。
66 yinzhengjie.Sing(高音唱)
67
68
69 fmt.Println(\n,strings.Repeat(*,30),我是分割线,strings.Repeat(*,30),\n)
70
71 yin : make([]Superman,3) //处理上面的那种最普遍的玩法当然也可以用make方法将其定义成切片的方式。
72 yin[0], yin[1], yin[2] hsy, bingan, yzj //用下标来区分不同的实力。这个时候我们可以发现Superman类型可以接受“Student”和“Teacher”类型的数据尽管这是两个不同的结构体但是照样可以通过一个接口来调用因此我叫它“大胃王”。
73
74 for _, value : range yin{ //然后我们就可以同时调用3个方法啦
75 value.SayHi()
76 }
77 }
78
79
80
81 #以上代码执行结果如下
82 Hello, my name is 【尹正杰】. My phone number is【7474741】.My home address is【北京】
83 【高音唱】我有一只小毛驴我从来也不骑有一天我心血来潮骑它去赶集.....
84
85 ****************************** 我是分割线 ******************************
86
87 Hello, my name is 【韩森雨】. My phone number is【2424241】.My home address is【北京】
88 Anyway, Im your 【Golang】 teacher, you can call me 【饼干】,My salary is...【30000.000000】
89 Hello, my name is 【尹正杰】. My phone number is【7474741】.My home address is【北京】 通过上面的代码我们可以知道interface 可以被任意的对象实现。同理一个对象可以实现任意多个interface。你会发现interface 就是一组抽象方法的集合它必须由其他非interface类型实现而不能自我实现 go 通过 interface 实现了duck-typing:即当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子那么这只鸟就可以被称为鸭子。 三.空interface 空interface(interface{})不包含任何的 method正因为如此所有的类型都实现了空interface。空 interface 对于描述起不到任何的作用(因为它不包含任何的 method但是空interface 在我们需要存储任意类型的数值的时候相当有用因为它可以存储任意类型的数值。一个函数把interface{}作为参数那么他可以接受任意类型的值作为参数如果一个函数返回interface{},那么也就可以返回任意类型的值。是不是瞬间就觉得interface很神奇 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import (
11 fmt
12 reflect
13 )
14
15 func Myecho(a interface{}) {
16 fmt.Printf(变量的值是\033[31;1m【%v】\033[0m其类型是\033[31;1m【%v】\033[0m\n,a,reflect.TypeOf(a))
17 }
18
19 func main() {
20 Name : 尹正杰 //我这里定义了三种不同的类型即字符串整数字节数等等。
21 Age : 18
22 Language : []byte(Golang)
23 fmt.Println(reflect.TypeOf(Name),reflect.TypeOf(Age),reflect.TypeOf(Language))
24 var yinzhengjie interface{} //定义一个空的interface由于每种数据类型都实现了空interface。因此我们利用这个特性可以接受任意类型的数据。
25 yinzhengjie Name
26 Myecho(yinzhengjie)
27 yinzhengjie Age
28 Myecho(yinzhengjie)
29 yinzhengjie Language
30 Myecho(yinzhengjie)
31 }
32
33
34
35 #以上代码输出结果如下
36 string int []uint8
37 变量的值是【尹正杰】其类型是【string】
38 变量的值是【18】其类型是【int】
39 变量的值是【[71 111 108 97 110 103]】其类型是【[]uint8】 四.interface 函数参数 interface 的变量可以持有任意实现该 interface 类型的对象这给我们编写函数(包括method)提供了一些额外的思考我们是不是可以通过定义 interface 参数让函数接受各种类型的参数。举个例子fmt.Println 是我们常用的一个函数但是你是否注意到它可以接受任意类型的数据。打开fmt的源码文件你会看到这样一个定义: 接下来我们就来模拟实现“fmt.Println()”的stringer方法吧 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import (
11 strconv
12 fmt
13 )
14
15 type Student struct {
16 Name string //定义姓名
17 age int //定义年龄
18 string //定义住址这是匿名字段
19 }
20
21 func (s Student)String()string { //给Student实现来String方法如果我们把String前面加个其他字母或是进行其他修改可能会导致该方法的内容不会被调用。
22 return My name is s.Name,I am strconv.Itoa(s.age) years old.I live in s.string
23 }
24
25 func main() {
26 yzj : Student{尹正杰,18,北京}
27 fmt.Println(This people is :,yzj)
28 }
29
30
31
32 #以上代码输出结果如下
33 This people is : My name is 尹正杰,I am 18 years old.I live in 北京 五.interface 变量存储的类型 我们知道interface 的变量里面可以存储任意类型的数值(该类型实现了interface)。那么我们怎么反向知道这个变量里面实际保存了的是哪个类型的对象呢目前常用的有两种方法“Comma-ok 断言” 和“switch 测试”。 1.Comma-ok 断言 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9 import (
10 fmt
11 strconv
12 )
13 type Element interface{}
14
15 const ( //这是定义一个常量的关键字
16 pi 3.14
17 )
18
19 type Student struct {
20 Name string
21 age int
22 }
23
24 //定义了 String 方法实现了fmt.Stringer
25 func (p Student) String() string {
26 return (name: p.Name - age: strconv.Itoa(p.age) years old!)
27 }
28 func main() {
29 list : make([]Element, 4)
30 list[0] 1 // 定义一个“int”类型的数据。
31 list[1] Hello // 定义一个“string”类型的数据。
32 list[2] Student{Yinzhengjie, 18} // 定义一个“Student”类型的数据。
33 list[3] pi //定义一个常量。
34
35 for index, element : range list { //接下来就是判断里面的每一个元素属于哪一种类型。
36 if value, ok : element.(int); ok { //判断当前的数据类型是否为“int”类型
37 fmt.Printf(list[%d] is an int and its value is %d\n, index, value)
38 } else if value, ok : element.(string); ok { //判断当前的数据类型是否为“string”类型
39 fmt.Printf(list[%d] is a string and its value is %s\n, index, value)
40 } else if value, ok : element.(Student); ok { //判断当前的数据类型是否为自定义的“Student”类型
41 fmt.Printf(list[%d] is a Student and its value is %s\n, index, value)
42 } else {
43 fmt.Printf(list[%d] is of a different type!, index)
44 }
45 }
46 }
47
48
49
50
51 #以上代码输出结果如下
52 list[0] is an int and its value is 1
53 list[1] is a string and its value is Hello
54 list[2] is a Student and its value is (name: Yinzhengjie - age: 18 years old!)
55 list[3] is of a different type! 2.switch 测试 如果上面的那种方式你能看懂并且之前我也分享过golang流程控制的笔记那么下面的这种断言方式对你来说就是小case啦~从代码的易读性的话我推荐使用这种方式进行对数据类型的断言。 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 9 package main
10
11 import (
12 strconv
13 fmt
14 )
15
16 type Element interface {}
17
18
19 type Student struct {
20 Name string
21 age int
22 }
23
24 func (p Student) String() string {
25 return My name is p.Name and I am strconv.Itoa(p.age) years old!
26 }
27
28 func main() {
29 list : make([]Element,3)
30 list[0] 1
31 list[1] yinzhengjie
32 list[2] Student{yinzhengjie,18}
33
34 for k,v : range list {
35 switch value : v.(type) { //element.(type) 语法不能在switch 外的任何逻辑里面使用如果你要在switch 外面判断一个类型就使用 comma-ok 。
36 case int:
37 fmt.Printf(list[%d] is an int and its value is %d\n,k,value)
38 case string:
39 fmt.Printf(list[%d] is an string and its value is %s\n,k,value)
40 case Student:
41 fmt.Printf(list[%d] is an Student and its value is %v\n,k,value)
42 default:
43 fmt.Printf(list[%d] is of a different\n,)
44 }
45 }
46 }
47
48
49
50
51 #以上代码输出结果如下
52 list[0] is an int and its value is 1
53 list[1] is an string and its value is yinzhengjie
54 list[2] is an Student and its value is My name is yinzhengjie and I am 18 years old! 六.嵌入 interface 看到官方使用的嵌入interface方法你是否想到我们之前说的匿名字段啦Go里面真正吸引人的是他内置的逻辑语法就像我们在学习Struct 时学习的匿名字段多么的优雅啊那么相同的逻辑引入到 interface 里面那不是更加完美了。如果一个interface1 作为 interface2 的一个嵌入字段那么 interface2 隐式的包含了interface1 里面的method。接下来我们就来举个例子自定义实现以下嵌入interface的案例吧具体代码如下 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import fmt
11
12 type Student struct { // 定义结构 Employee
13 Name string
14 age int
15 salary int
16 gender string
17 }
18
19 // 定义结构 Employee 的方法
20 func (self *Student) GetName() string {
21 return self.Name
22 }
23
24 func (self *Student) GetAge() int {
25 return self.age
26 }
27
28 func (self *Student) GetSalary() int {
29 return self.salary
30 }
31
32 func (self *Student) Help() {
33 fmt.Println(Dont ask me, ask me, I wont tell you!)
34 }
35
36 func (self *Student) GetGender() string {
37 return self.gender
38 }
39
40 type MiyoshiStudents interface { // 定义接口类型 MiyoshiStudents 包含获取基本信息的方法
41 GetName() string
42 GetAge() int
43 }
44
45 type Teacher interface { // 定义接口类型 Teacher 包含获取薪水的方法且 Teacher 接口中嵌入了 MiyoshiStudents 接口前者将获取后者的所有方法。
46 MiyoshiStudents //这就是嵌入interface和嵌入匿名字段的用法有点相似。
47 GetSalary() int
48 Help()
49 }
50
51 func main() {
52 yzj : Student{ // yzj 实现了 MiyoshiStudents 和 Teacher 这两个接口
53 Name: 尹正杰,
54 age: 18,
55 salary: 100000000,
56 gender: Male,
57 }
58 fmt.Println(yzj is: , yzj)
59 yzj.Help()
60 fmt.Println(yzj.name , yzj.GetName())
61 fmt.Println(yzj.age , yzj.GetAge())
62 fmt.Println(yzj.salary , yzj.GetSalary())
63
64 var yinzhengjie Teacher yzj
65
66 switch yinzhengjie.(type) { // 接口类型转换从超集到子集的转换是可以的,从方法集的子集到超集的转换会导致编译错误,这种情况下 switch 不支持 fallthrough。
67 case nil:
68 fmt.Println(空接口nil)
69 case MiyoshiStudents:
70 fmt.Println(MiyoshiStudents 接口)
71 default:
72 fmt.Println(位置接口)
73 }
74 }
75
76
77
78
79 #以上代码执行结果如下
80 yzj is: {尹正杰 18 100000000 Male}
81 Dont ask me, ask me, I wont tell you!
82 yzj.name 尹正杰
83 yzj.age 18
84 yzj.salary 100000000
85 MiyoshiStudents 接口 七.匿名接口 还记得匿名字段吗我们可以在一个结构体中定义一个匿名字段这个匿名字段可以是内置的也可以是我们自定义的而interface是一种特殊的数据类型因为golang认为所有的数据类型都实现了空接口也就是说所有数据都是空interface的子集。换句话说我们可以说一个空的interface是可以接受任何类型的数据的。通过这一点它会给我们很多启发吗我们可以通过interface来接受任何类型的参数也可以通过interface来返回任何类型的参数接下来我们一起看下匿名interface的使用案例吧 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import fmt
11
12
13 type Student struct { // 定义结构体Student
14 Name string
15 age int
16 salary int
17 gender string
18 }
19
20 func (self *Student) GetName() string { // 定义结构 Student 的方法
21 return self.Name
22 }
23
24 func (self *Student) GetAge() int {
25 return self.age
26 }
27
28 func (self *Student) GetSalary() int {
29 return self.salary
30 }
31
32 func (self *Student) Help() {
33 fmt.Println(This is help info.)
34 }
35
36 type MiyoshiStudents struct {
37 GetInfo interface { // 匿名接口可以被用作变量或者结构属性类型我们定义了一个“GetInfo”的匿名接口里面可以存储各种数据属性。
38 GetGender() string
39 GetSalary() int
40 GetAge() int
41 GetName() string
42 }
43 }
44
45 func (self *Student) GetGender() string {
46 return self.gender
47 }
48
49
50 func main() {
51 yzj : MiyoshiStudents{Student{ // 匿名接口对象的使用
52 Name: 尹正杰,
53 age: 18,
54 salary: 10000000000,
55 gender: 男孩,
56 }}
57 fmt.Println(姓名,yzj.GetInfo.GetName())
58 fmt.Println(年龄,yzj.GetInfo.GetAge())
59 fmt.Println(性别: , yzj.GetInfo.GetGender())
60 fmt.Println(期望薪资,yzj.GetInfo.GetSalary())
61
62 }
63
64
65
66 #以上代码运行结果如下
67 姓名 尹正杰
68 年龄 18
69 性别: 男孩
70 期望薪资 10000000000 八.进阶知识-Go语言的反射三定律 1.什么是反射 反射是指程序可以访问、检测和修改它本身状态或行为的一种能力所以给的定义就是说明了它能干嘛。我们平时用反射主要做获取类型的相关信息动态调用方法动态构造对象从程序集中获得类型。 2.为什么需要反射 Go是静态类型语言。每个变量都有且只有一个静态类型在编译时就已经确定。尽管变量两个边路都具有共同的底层数据类型但它们的只要他们静态类型不一样。不经过类型转换直接相互赋值时编译器会报错。相信大家通过一段熟悉的代码就应该明白了 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import fmt
11
12 type Myint int
13
14 type Element interface{} //定义一个空接口
15
16 var (
17 x int
18 y Myint //尽管变量 x 和 y 具有共同的底层类型 int但它们的静态类型并不一样。
19 )
20 func main() {
21 x 100
22 y 100
23 list : make([]Element, 2)
24 list[0] x
25 list[1] y
26 fmt.Println(list)
27 for k,v : range list{
28 switch value : v.(type) { //我们队数据类型进行断言。
29 case int:
30 fmt.Printf(list[%d] is an int(整型) and its value is %d\n,k,value)
31 case string:
32 fmt.Printf(list[%d] is an string字符串 and its value is %d\n,k,value)
33 case Myint:
34 fmt.Printf(list[%d] is an Myint自定义类型 and its value is %d\n,k,value)
35 default:
36 fmt.Printf(list[%d] is of a different\n,)
37 }
38 }
39 }
40
41
42
43
44 #以上代码执行结果如下
45 [100 100]
46 list[0] is an int(整型) and its value is 100
47 list[1] is an Myint自定义类型 and its value is 100 3.反射第一定律从接口值到反射对象的反射Reflection goes from interface value to reflection object 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import (
11 fmt
12 reflect
13 )
14
15 func main() {
16 var yzj float64 5.2
17 fmt.Println(type:, reflect.TypeOf(yzj)) //reflect.Typeof 签名里就包含了一个空接口。当我们调用reflect.Typeof(yzj)的时候
18 // yzj首先被保存到一个空接口中这个空接口然后被作为参数传递。reflect.Typeof 会把这个空接口拆包unpack恢复出类型信息。
19
20 fmt.Println(value:, reflect.ValueOf(yzj)) //当然reflect.Valueof可以把值恢复出来,Valueof方法会返回一个Value类型的对象
21 }
22
23
24
25 #以上代码执行结果如下
26 type: float64
27 value: 5.2 reflect.Type和reflect.Value这两种类型都提供了大量的方法让我们可以检查和操作这两种类型。有以下两点要注意 第一Value类型有一个Type方法可以返回reflect.Value类型的Type这个方法返回的是值的静态类型即“static type”也就是说如果定义了“type MyType string”那么这个函数返回的是“MyType”类型而不是“string”。有关Value类型的带有名字诸如“String”,“Int”,“Uint”“Bytes”等等的方法可让我们获取存在里面的值。 第二Type和Value都有一个Kind方法可以返回一个常量用于指示一个项到底是以什么形式存储的也就是底层类型即“underlying type”。这些常量包括Unit, Float64, Slice等等。 具体用法我们可以以下的代码 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import (
11 reflect
12 fmt
13 )
14
15 type MyType string
16
17 func main() {
18 var y MyType yinzhengjie
19 Type : reflect.TypeOf(y) //得到类型的元数据,通过 t 我们能获取类型定义里面的所有元素.
20 Value : reflect.ValueOf(y) //得到实际的值通过 v 我们获取存储在里面的值还可以去改变值.
21 fmt.Println(type\t\t\t:,Type)
22 fmt.Println(underlying type :,Type.Kind()) //Type和Value都有一个Kind方法可以返回一个常量以判断出它的底层数据到底是什么类型。
23 fmt.Println(value\t\t\t:,Value)
24 fmt.Println(static type :,Value.Type()) //Value类型有一个Type方法可以返回reflect.Value类型的Type这个方法返回的是值的静态类型即static type.
25 fmt.Println(underlying type :,Value.Kind())
26 fmt.Println(kind is string :,Value.Kind() reflect.String)
27 fmt.Println(value\t\t\t:,Value.String()) //通过Value类型String方法来让我们获取存在里面的值。如果是底层数据是“int”就用“Int”方法获取。
28 }
29
30
31
32
33 #以上代码执行结果如下
34 type : main.MyType
35 underlying type : string
36 value : yinzhengjie
37 static type : main.MyType
38 underlying type : string
39 kind is string : true
40 value : yinzhengjie 4.反射第二定律从反射对象到接口值的反射Reflection goes from reflection object to interface value 就像物理学上的作用力和反作用力我们可以从接口值到反射对象与此同时我们也可以从反射对象到接口值。 给定一个reflect.Value我们能用Interface方法把它恢复成一个接口值效果上就是这个Interface方法把类型和值的信息打包成一个接口表示并且返回结果。简要的说Interface方法是Valueof函数的逆除了它的返回值的类型总是interface{}静态类型。重申一遍反射就是从接口值到反射对象然后再反射回来。Reflection goes from interface value to reflection object and back again. 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import (
11 reflect
12 fmt
13 )
14
15 type MyType string
16
17
18 func main() {
19 var y MyType yinzhengjie
20 Value : reflect.ValueOf(y) //得到实际的值通过 v 我们获取存储在里面的值还可以去改变值.
21 fmt.Println(Value) //Value是一个reflect.Value.
22
23 x : Value.Interface() //我们想要的是Value里面保存的具体值.我们不需要对v.Interface方法的结果调用类型断言
24 fmt.Println(x)
25 }
26
27
28
29 #以上代码执行结果如下
30 yinzhengjie
31 yinzhengjie 5.反射第三定律为了修改一个反射对象值必须是settable的To modify a reflection object, the value must be settable) 1 /*2 #!/usr/bin/env gorun3 author :yinzhengjie4 Blog:http://www.cnblogs.com/yinzhengjie/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/5 EMAIL:y1053419035qq.com6 */7 8 package main9
10 import (
11 reflect
12 fmt
13 )
14
15 func main() {
16 var yzj string yinzhengjie
17 p : reflect.ValueOf(yzj) //注意这里哦我们把yzj地址传进去了
18 fmt.Println(type of p:, p.Type()) //我们是讲地址传进去的所以得到的应该是一个指针类型的string.
19 fmt.Println(settability of p:, p.CanSet()) //反射对象p不是settable的,因此返回值应该是一个false!
20
21 v : p.Elem() //反射对象p不是settable的但是我们想要设置的不是p而是效果上来说*p,为了得到p指向的东西我们调用Value的Elem方法。
22
23 fmt.Println(v.Interface()) //查看v里面的值
24 s : v.String()
25 s 尹正杰 //我们此处修改的只是“yzj”变量中的一个副本
26 fmt.Println(s)
27 fmt.Println(yzj) //忧郁s修改的是副本所以对本尊是一点影响的都没有的源数据应该还是“yinzhengjie”
28
29
30 fmt.Println(settability of v:, v.CanSet()) //反射对象v是settable的,因此返回值应该是一个true!
31 v.SetString(Golang) //想要修改源数据还是得调用该SetStringSetInt,SetFloat,等方法去修改相应的数据类型。
32 fmt.Println(yzj) //由于已经通过SetString方法对源数据进行了修改因此我们再看yzj这个变量的值就已经被修改了。
33 }
34
35
36
37
38 #以上代码执行结果如下
39 type of p: *string
40 settability of p: false
41 yinzhengjie
42 尹正杰
43 yinzhengjie
44 settability of v: true
45 Golang 转载于:https://www.cnblogs.com/yinzhengjie/p/7733420.html