Go語(yǔ)言開發(fā)框架反射機(jī)制及常見函數(shù)示例詳解
基本介紹
- 反射可以在運(yùn)行時(shí)動(dòng)態(tài)獲取變量的各種信息,比如變量的類型,類別
- 如果是結(jié)構(gòu)體變量,還可以獲取到結(jié)構(gòu)體本身的信息
- 通過(guò)反射,可以修改變量的值,可以調(diào)用關(guān)聯(lián)的方法
- 使用反射,需要import("reflect")
示意圖

反射中常見函數(shù)和概念
reflect.TypeOf(變量名)
獲取變量的類型,返回reflect.Type類型
reflect.ValueOf(變量名)
獲取變量的值,返回reflect.Value類型reflect.Value是一個(gè)結(jié)構(gòu)體類型,通過(guò)reflect.Value,可以獲取到關(guān)于該變量的很多信息
變量.interface{}和reflect.Value是可以相互轉(zhuǎn)換的

基本使用
package main
import (
"fmt"
"reflect"
)
/*
1.編寫案例,對(duì)基本數(shù)據(jù)類型,interface{},reflect.Value進(jìn)行反射
2.編寫案例,對(duì)結(jié)構(gòu)體,interface{},reflect.Value進(jìn)行反射
*/
func reflectTest(b interface{}){
//打印出傳參的type,kind,value
fmt.Printf("b的類型為%v,b的kind為%v,value為%v\n",reflect.TypeOf(b),reflect.ValueOf(b).Kind(),reflect.ValueOf(b)) //b的類型為int,b的kind為int,value為100
//reflect.TypeOf(),reflect.ValueOf()返回的類型
fmt.Printf("reflect.TypeOf()返回類型為%T,reflect.ValueOf()返回類型為%T\n",reflect.TypeOf(b),reflect.ValueOf(b)) //reflect.TypeOf()返回類型為*reflect.rtype,reflect.ValueOf()返回類型為reflect.Value
}
type Student struct {
Name string
age int
}
func reflectTest2(b interface{}){
rTyp:=reflect.TypeOf(b)
fmt.Println(rTyp) //main.Student
rVal:=reflect.ValueOf(b)
//將rVal轉(zhuǎn)換成interface{}
iV:=rVal.Interface()
fmt.Printf("iv=%v type=%T\n",iV,iV) //iv={張三 18} type=main.Student
//因?yàn)镚o語(yǔ)言是靜態(tài)語(yǔ)言,所以不能直接獲取結(jié)構(gòu)體中指定的值,所以我需要將其斷言成需要的類型
stu,ok:=iV.(Student)
if ok{
fmt.Printf(stu.Name,stu.age) //張三%!(EXTRA int=18)
}
}
func main() {
//1.編寫案例,對(duì)基本數(shù)據(jù)類型,interface{},reflect.Value進(jìn)行反射
var num int =100
reflectTest(num)
//2.編寫案例,對(duì)結(jié)構(gòu)體,interface{},reflect.Value進(jìn)行反射
stu:=Student{
Name: "張三",
age: 18,
}
reflectTest2(stu)
}
反射注意事項(xiàng)
- reflect.ValueKind,獲取的變量的類別,返回的是一個(gè)常量
- Type是類型,Kind是類別,Type和Kind可能是相同的,也可能是不同的,例如結(jié)構(gòu)體
- 通過(guò)反射可以在讓變量在interface{}和reflect.Value之間相互轉(zhuǎn)換
- 通過(guò)反射的方式獲取變量的值(并返回對(duì)應(yīng)的類型),要求數(shù)據(jù)類型匹配,比如x是int,那么就應(yīng)該使用reflect.Value(x).Int(),而不能使用其他的,否則報(bào)panic
- 通過(guò)反射來(lái)修改變量,注意當(dāng)使用Setxxx方法來(lái)設(shè)置需要通過(guò)對(duì)應(yīng)的指針類型來(lái)完成,這樣才能改變傳入變量的值,同時(shí)需要使用到reflect.Value.Elem()方法
反射的最佳實(shí)踐
使用反射來(lái)遍歷結(jié)構(gòu)體的字段,調(diào)用結(jié)構(gòu)體的方法,并獲取結(jié)構(gòu)體標(biāo)簽的值
package main
import (
"fmt"
"reflect"
)
//定義了一個(gè)Monster結(jié)構(gòu)體
type Monster struct {
Name string `json:"name"`
Age int `json:"monster_age"`
Score float32 `json:"成績(jī)"`
Sex string
}
//方法,返回兩個(gè)數(shù)的和
func (s Monster) GetSum(n1, n2 int) int {
return n1 + n2
}
//方法, 接收四個(gè)值,給s賦值
func (s Monster) Set(name string, age int, score float32, sex string) {
s.Name = name
s.Age = age
s.Score = score
s.Sex = sex
}
//方法,顯示s的值
func (s Monster) Print() {
fmt.Println("---start~----")
fmt.Println(s)
fmt.Println("---end~----")
}
func TestStruct(a interface{}) {
//獲取reflect.Type 類型
typ := reflect.TypeOf(a)
//獲取reflect.Value 類型
val := reflect.ValueOf(a)
//獲取到a對(duì)應(yīng)的類別
kd := val.Kind()
//如果傳入的不是struct,就退出
if kd != reflect.Struct {
fmt.Println("expect struct")
return
}
//獲取到該結(jié)構(gòu)體有幾個(gè)字段
num := val.NumField()
fmt.Printf("struct has %d fields\n", num) //4
//變量結(jié)構(gòu)體的所有字段
for i := 0; i < num; i++ {
fmt.Printf("Field %d: 值為=%v\n", i, val.Field(i))
//獲取到struct標(biāo)簽, 注意需要通過(guò)reflect.Type來(lái)獲取tag標(biāo)簽的值
tagVal := typ.Field(i).Tag.Get("json")
//如果該字段于tag標(biāo)簽就顯示,否則就不顯示
if tagVal != "" {
fmt.Printf("Field %d: tag為=%v\n", i, tagVal)
}
}
//獲取到該結(jié)構(gòu)體有多少個(gè)方法
numOfMethod := val.NumMethod()
fmt.Printf("struct has %d methods\n", numOfMethod)
//var params []reflect.Value
//方法的排序默認(rèn)是按照 函數(shù)名的排序(ASCII碼)
val.Method(1).Call(nil) //獲取到第二個(gè)方法。調(diào)用它
//調(diào)用結(jié)構(gòu)體的第1個(gè)方法Method(0)
var params []reflect.Value //聲明了 []reflect.Value
params = append(params, reflect.ValueOf(10))
params = append(params, reflect.ValueOf(40))
res := val.Method(0).Call(params) //傳入的參數(shù)是 []reflect.Value, 返回[]reflect.Value
fmt.Println("res=", res[0].Int()) //返回結(jié)果, 返回的結(jié)果是 []reflect.Value*/
}
func main() {
//創(chuàng)建了一個(gè)Monster實(shí)例
var a Monster = Monster{
Name: "黃鼠狼精",
Age: 400,
Score: 30.8,
}
//將Monster實(shí)例傳遞給TestStruct函數(shù)
TestStruct(a)
}
以上就是Go語(yǔ)言開發(fā)框架反射機(jī)制及常見函數(shù)示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Go開發(fā)框架反射機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go中各種newreader和newbuffer的使用總結(jié)
這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中各種newreader和newbuffer的使用的相關(guān)資料,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴可以了解下2023-11-11
詳解如何在Golang中監(jiān)聽多個(gè)channel
這篇文章主要為大家詳細(xì)介紹了如何在Golang中實(shí)現(xiàn)監(jiān)聽多個(gè)channel,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03
GoLand一鍵上傳項(xiàng)目到遠(yuǎn)程服務(wù)器的方法步驟
我們開發(fā)項(xiàng)目常常將項(xiàng)目上傳到linux遠(yuǎn)程服務(wù)器上來(lái)運(yùn)行,本文主要介紹了GoLand一鍵上傳項(xiàng)目到遠(yuǎn)程服務(wù)器的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
詳解Go語(yǔ)言中Goroutine退出機(jī)制的原理及使用
goroutine是Go語(yǔ)言提供的語(yǔ)言級(jí)別的輕量級(jí)線程,在我們需要使用并發(fā)時(shí),我們只需要通過(guò)?go?關(guān)鍵字來(lái)開啟?goroutine?即可。本文就來(lái)詳細(xì)講講Goroutine退出機(jī)制的原理及使用,感興趣的可以了解一下2022-07-07
Go垃圾回收提升內(nèi)存管理效率優(yōu)化最佳實(shí)踐
這篇文章主要為大家介紹了Go垃圾回收提升內(nèi)存管理效率優(yōu)化最佳實(shí)踐,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
Golang實(shí)現(xiàn)定時(shí)任務(wù)的幾種方法小結(jié)
在 Golang 開發(fā)中,定時(shí)任務(wù)是常見的需求,本文將介紹幾種在 Golang 中實(shí)現(xiàn)定時(shí)任務(wù)的方法,包括 time 包的定時(shí)器、ticker,以及第三方庫(kù) cron,并通過(guò)示例代碼展示它們的使用方式,需要的朋友可以參考下2024-01-01
Golang連接池的幾種實(shí)現(xiàn)案例小結(jié)
這篇文章主要介紹了Golang連接池的幾種實(shí)現(xiàn)案例小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
Go通過(guò)goroutine實(shí)現(xiàn)多協(xié)程文件上傳的基本流程
多協(xié)程文件上傳是指利用多線程或多協(xié)程技術(shù),同時(shí)上傳一個(gè)或多個(gè)文件,以提高上傳效率和速度,本文給大家介紹了Go通過(guò)goroutine實(shí)現(xiàn)多協(xié)程文件上傳的基本流程,需要的朋友可以參考下2024-05-05

