Golang 全面展示反射技术使用 一

package main

import (
"fmt"
"reflect"
)

//父对象
type Human struct {
name string //私有字段
//Age是公有字段定义方式(反射可修改它的值),age是私有字段定义方式(反射不可修改它的值)
Age int //公有字段
phone string //私有字段
}

//子对象,因为有了匿名字段,所以就继承了父对象Human的所有字段,还有父对象已经实现了的方法
type Student struct {
Human //匿名字段
school string //私有字段
//Loan是公有字段定义方式(反射可修改它的值),loan是私有字段定义方式(反射不可修改它的值)
Loan float32 //借款
}

//子对象,因为有了匿名字段,所以就继承了父对象Human的所有字段,还有父对象已经实现了的方法
type Employee struct {
Human //匿名字段
company string //私有字段
//Money是公有字段定义方式(反射可修改它的值),money是私有字段定义方式(反射不可修改它的值)
Money float32 //花钱
}

//在多个对象共有的匿名字段Human上面定义了一个方法,这个方法就是一个继承方法
func (h *Human) SayHi() (hi string) {
hi = h.name + " Said: Hi,I am " + h.name + " you can call me on " + h.phone
return hi
}

//Employee的method重写继承Human的method
func (e *Employee) SayHi() (hi string) {
hi = e.name + " Said: Hi,I am " + e.name + " I work at " + e.company + ". Call me on " + e.phone
return hi
}

//给两个子对象Student和Employee添加一个继承方法,只需要在父对象Human上实现该方法即可
func (h *Human) Sing(song string) (out string) {
out = h.name + " is singing the song - " + song //谁在唱歌
return out
}

//给两个子对象Student和Employee添加一个继承方法,只需要在父对象Human上实现该方法即可
func (h *Human) Guzzle(beer string) (out string) {
out = h.name + " is guzzling his/her beer - " + beer //谁在狂饮啤酒
return out
}

//Student实现BorrowMoney方法
func (s *Student) BorrowMoney(amount float32) (out float32) {
s.Loan += amount //累加借款的金额
out = s.Loan
return out
}

//Employee实现SpendSalary方法
func (e *Employee) SpendSalary(amount float32) (out float32) {
e.Money -= amount //累减剩余的薪水
out = e.Money
return out
}

//以下3个接口内部的方法,返回值参数的名称及其类型必须显式地声明

// 定义男子汉接口
type Men interface {
SayHi() (hi string)
Sing(song string) (out string)
Guzzle(beer string) (out string)
}

//定义小伙子接口
type YoungChap interface {
SayHi() (hi string)
Sing(song string) (out string)
BorrowMoney(amount float32) (out float32)
}

//定义老先生接口
type ElderlyGent interface {
SayHi() (hi string)
Sing(song string) (out string)
SpendSalary(amount float32) (out float32)
}

//Go语言的反射技术范例
func main() {
mm := make(map[int]string,5)
mm[1] = "aaaa"
mm[2] = "bbbb"
mm[3] = "cccc"
mm[4] = "dddd"
mm[5] = "eeee"
mm[6] = "ffff"
fmt.Println(len(mm)) // cap(mm) cap是不能计算机map的容量

m := make([]map[int]chan string,5,10)
fmt.Println(len(m),cap(m)) // 5 10
x := 3.69
y := 0.01
z1 := x + y
fmt.Printf("%v\n",z1) // output: 3.6999999999999997
z2 := (x + y) * 100 / 100
fmt.Printf("%0.2f\n",z2) // output: 3.70

mike := Student{Human{"Mike",25,"222-222-XXX"},"MIT",0.00} //小伙子
jack := Student{Human{"Jack",21,"222-222-4579"},"Tsinghua",1500.00} //小伙子
tom := Student{Human{"Tom",29,"222-222-4548"},"Peking",3200.00} //男子汉
paul := Student{Human{"Paul",26,"111-222-1314"},"Harvard",100} //小伙子
tim := Employee{Human{"Tim",35,"222-222-9948"},"Sina",7500.00} //男子汉
kite := Employee{Human{"Kite",36,"222-222-7848"},"Sohu",10500.00} //男子汉
sam := Employee{Human{"Sam",58,"444-222-5520"},"Golang Inc.",8000} //老先生

//定义Men切片
slMen := make([]Men,3)
//这三个对象有2种不同类型的元素(学生和职员)
//所有元素都能存储到YoungChap、Men和ElderlyGent接口里,因为它们本质上都是interface的别名
slMen[0],slMen[1],slMen[2] = &paul,&sam,&mike //注意:这样赋值超过3个会越界
//使用 append 追加动态扩容切片的大小,让超过3个的对象也可以存储到接口的切片里
slMen = append(slMen,&jack,&tom,&kite) //append方法会分配新的内存空间存储无法装进来的数据

fmt.Println("------------------- 反射 -------------------")
p1 := reflect.ValueOf(&tom)
p1 = reflect.Indirect(p1) //此行代码等价于 p1 = p1.Elem()
v1 := p1.FieldByName("Loan")
if v1.Kind() == reflect.Float32 {
if v1.CanSet() {
v1.SetFloat(3650.88)
}
}
fmt.Println("reflect.ValueOf(&tom) is ",p1)
fmt.Println("p1 = reflect.Indirect(p1) is ",p1)
fmt.Println(`v1 := p1.FieldByName("Loan") is `,v1)
fmt.Println("tom is ",tom)
fmt.Println("------------------- 反射 -------------------")

p2 := reflect.ValueOf(&tim)
v2 := p2.Elem()
//直接出现panic,问题出在money字段首字母小写定义的是私有字段,反射无法修改
v2.Field(2).SetFloat(3650.88)

fmt.Println("reflect.ValueOf(&tim) is ",p2)
fmt.Println("p2.Elem() is ",p2.Elem())
fmt.Println("v2 := p2.Elem() is ",v2)
fmt.Println("tim is ",tim)

v2.Field(0).FieldByName("Age").SetInt(37) //修改父对象Human里的公有字段Age的值
fmt.Println("tim is ",tim)
fmt.Println("--------------------------- 反射 ----------------------------------------")

var input1 float32 = 1300.25 // 等价于 input1 := float32(1300.25)
m1 := reflect.ValueOf(&jack).MethodByName("BorrowMoney")
output1 := m1.Call([]reflect.Value{reflect.ValueOf(input1)})
fmt.Println(output1)
fmt.Println(output1[0])

m2 := reflect.ValueOf(&jack).MethodByName("SayHi")
output2 := m2.Call([]reflect.Value{})
fmt.Println(output2)
fmt.Println(output2[0])
fmt.Println("--------------------------- 反射 ----------------------------------------")

//定义男子汉Men接口类型的变量inMen
var inMen Men
//Men能存储Employee
//因为实现男子汉接口内部的方法时,这些方法的接收参数使用了指针,所以给接口切片赋值时必须使用对象的地址赋值
inMen = &tim
hi4 := inMen.SayHi()
out3 := inMen.Sing("Born to be wild")
out4 := inMen.Guzzle("Budweiser")
fmt.Println(hi4)
fmt.Println(out3)
fmt.Println(out4)
fmt.Println("--------------------------------------")

obj := reflect.ValueOf(&tim)
element := obj.Elem()
typeOfElem := element.Type()
fmt.Println(typeOfElem,obj.Type())
fmt.Println(typeOfElem.Field(0))
fmt.Println("output: ",element.Field(0).Interface()) //output: {Tim 37 222-222-9948}
fmt.Println("output: ",element.Field(0).Interface().(Human).name) //output: Tim
fmt.Println("output: ",element.Field(0).Interface().(Human).Age) //output: 37
fmt.Println("output: ",reflect.TypeOf(element.Field(0).Interface().(Human).Age)) //output: int
fmt.Println("output: ",element.Field(0).Interface().(Human)) //output: {Tim 37 222-222-9948}
fmt.Println("output: ",element.FieldByName("Human")) //output: {Tim 37 222-222-9948}
fmt.Println("output: ",element.FieldByName("Human").Type()) //output: main.Human
for i := 0; i < element.NumField(); i++ {
fmt.Println("typeOfElem.Field(",i,").Name :",typeOfElem.Field(i).Name,"element.Field(",").Type() :",element.Field(i).Type(),") :",element.Field(i))
if typeOfElem.Field(i).Name == "Human" {
for j := 0; j < element.Field(i).NumField(); j++ {
fmt.Println(element.FieldByName("Human").Type().Field(j).Name,element.Field(i).Field(j).Type(),element.Field(i).Field(j))
// v.Kind() == reflect.Float64 // 判断字段的类型
}
}
}

fmt.Println("----------------- 反射调用切片接口类型的对象 ---------------------")
fmt.Println(slMen[0])
fmt.Println(reflect.ValueOf(slMen[0]))
inMen2 := reflect.ValueOf(slMen[0])
element2 := inMen2.Elem()
typeOfElem2 := element2.Type()
fmt.Println(typeOfElem2,inMen2.Type())
fmt.Println(typeOfElem2.Field(0))
fmt.Println("output: ",element2.Field(0).Interface()) //output: {Paul 26 111-222-1314}
fmt.Println("output: ",element2.Field(0).Interface().(Human).name) //output: Paul
fmt.Println("output: ",element2.Field(0).Interface().(Human).Age) //output: 26
fmt.Println("output: ",reflect.TypeOf(element2.Field(0).Interface().(Human).Age)) //output: int
fmt.Println("output: ",element2.Field(0).Interface().(Human)) //output: {Paul 26 111-222-1314}
fmt.Println("output: ",element2.FieldByName("Human")) //output: {Paul 26 111-222-1314}
fmt.Println("output: ",element2.FieldByName("Human").Type()) //output: main.Human

var input12 = "Snow Bear" // 等价于 input12 := "Snow Bear"
m12 := reflect.ValueOf(slMen[0]).MethodByName("Guzzle")
output12 := m12.Call([]reflect.Value{reflect.ValueOf(input12)})
fmt.Println(output12)
fmt.Println(output12[0])
fmt.Println("inMen2 :",inMen2,"inMen2.Type() :",inMen2.Type())
/* output : inMen2 : &{{Paul 26 111-222-1314} Harvard 100} inMen2.Type() : *main.Student */
//输出所有方法
for i := 0; i < inMen2.NumMethod(); i++ {
fmt.Println(inMen2.Type().Method(i).Name,inMen2.Type().Method(i).Type)
/*
output :
BorrowMoney func(*main.Student,float32) float32
Guzzle func(*main.Student,string) string
SayHi func(*main.Student) string
Sing func(*main.Student,string) string
*/
}

}




控制台输出:

2017/06/17 15:22:13 server.go:73: Using API v1
2017/06/17 15:22:13 debugger.go:97: launching process with args: [/root/code/go/src/contoso.org/hello/debug]
API server listening at: 127.0.0.1:2345
2017/06/17 15:22:14 debugger.go:505: continuing
6
5 10
3.6999999999999997
3.70
------------------- 反射 -------------------
reflect.ValueOf(&tom) is {{Tom 29 222-222-4548} Peking 3650.88}
p1 = reflect.Indirect(p1) is {{Tom 29 222-222-4548} Peking 3650.88}
v1 := p1.FieldByName("Loan") is 3650.88
tom is {{Tom 29 222-222-4548} Peking 3650.88}
------------------- 反射 -------------------
reflect.ValueOf(&tim) is &{{Tim 35 222-222-9948} Sina 3650.88}
p2.Elem() is {{Tim 35 222-222-9948} Sina 3650.88}
v2 := p2.Elem() is {{Tim 35 222-222-9948} Sina 3650.88}
tim is {{Tim 35 222-222-9948} Sina 3650.88}
tim is {{Tim 37 222-222-9948} Sina 3650.88}
--------------------------- 反射 ----------------------------------------
[<float32 Value>]
2800.25
[Jack Said: Hi,I am Jack you can call me on 222-222-4579]
Jack Said: Hi,I am Jack you can call me on 222-222-4579
--------------------------- 反射 ----------------------------------------
Tim Said: Hi,I am Tim I work at Sina. Call me on 222-222-9948
Tim is singing the song - Born to be wild
Tim is guzzling his/her beer - Budweiser
--------------------------------------
main.Employee *main.Employee
{Human main.Human 0 [0] true}
output: {Tim 37 222-222-9948}
output: Tim
output: 37
output: int
output: {Tim 37 222-222-9948}
output: {Tim 37 222-222-9948}
output: main.Human
typeOfElem.Field( 0 ).Name : Human element.Field( 0 ).Type() : main.Human element.Field( 0 ) : {Tim 37 222-222-9948}
name string Tim

Age int 37 phone string 222-222-9948 typeOfElem.Field( 1 ).Name : company element.Field( 1 ).Type() : string element.Field( 1 ) : Sina typeOfElem.Field( 2 ).Name : Money element.Field( 2 ).Type() : float32 element.Field( 2 ) : 3650.88 ----------------- 反射调用接口类型的对象 --------------------- &{{Paul 26 111-222-1314} Harvard 100} &{{Paul 26 111-222-1314} Harvard 100} main.Student *main.Student {Human main.Human 0 [0] true} output: {Paul 26 111-222-1314} output: Paul output: 26 output: int output: {Paul 26 111-222-1314} output: {Paul 26 111-222-1314} output: main.Human [Paul is guzzling his/her beer - Snow Bear] Paul is guzzling his/her beer - Snow Bear inMen2 : &{{Paul 26 111-222-1314} Harvard 100} inMen2.Type() : *main.Student BorrowMoney func(*main.Student,float32) float32 Guzzle func(*main.Student,string) string SayHi func(*main.Student) string Sing func(*main.Student,string) string

相关文章

类型转换 1、int转string 2、string转int 3、string转float ...
package main import s &quot;strings&quot; import...
类使用:实现一个people中有一个sayhi的方法调用功能,代码如...
html代码: beego代码:
1、读取文件信息: 2、读取文件夹下的所有文件: 3、写入文件...
配置环境:Windows7+推荐IDE:LiteIDEGO下载地址:http:...