深入了解Golang中reflect反射的使用
1. 介紹
在反射的世界里,我們擁有了獲取一個(gè)對(duì)象的類型,屬性及方法的能力。
在 Go 反射的世界里,有兩種類型非常重要,是整個(gè)反射的核心,在學(xué)習(xí) reflect 包的使用時(shí),先得學(xué)習(xí)下這兩種類型:
- reflect.Type
- reflect.Value
2. 方法示例
2.1 通過(guò)反射獲取對(duì)象的鍵(類型)和值
package main import ( "fmt" "reflect" ) // func reflectNum(arg interface{}) { fmt.Println("type:",reflect.TypeOf(arg)) fmt.Println("value : ",reflect.ValueOf(arg)) } func main() { reflectNum(1.1234) }
type: float64
value : 1.1234
注意,Go 中所有對(duì)象都是鍵+值組成的,含有這種特性的對(duì)象都是可以用 Type + Value 進(jìn)行抽象的,這就是萬(wàn)能對(duì)象
2.2 反射對(duì)象的類型和屬性
package main import ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (this User) Call() { fmt.Println("user is called ..") fmt.Printf("#{this}\n") } func main() { user := User{1,"Aceld",18} //傳入 user 對(duì)象 DoFiledAndMethod(user) } //接收萬(wàn)能對(duì)象 用反射解析 func DoFiledAndMethod(input interface{}) { //反射獲取類的類型 inputType := reflect.TypeOf(input) fmt.Println("inputType is :", inputType.Name() ) // inputType is : User inputValue := reflect.ValueOf(input) fmt.Println("inputValue is :", inputValue) //inputValue is : {1 Aceld 18} //反射獲取類的屬性 for i := 0; i < inputType.NumField(); i++ { field := inputType.Field(i) value := inputValue.Field(i).Interface() fmt.Printf("%s : %v = %v\n",field.Name,field.Type,value) //Id : int = 1 //Name : string = Aceld //Age : int = 18 } //反射調(diào)用方法 for i := 0; i < inputType.NumMethod(); i++ { m := inputType.Method(i) //%s 輸出字符串表示(string類型或[]byte) //%v 相應(yīng)值的默認(rèn)格式。 fmt.Printf("%s:%v\n",m.Name,m.Type) //Call:func(main.User) } }
3. 反射對(duì)Json的操作
3.1 反射與Json屬性解析
在結(jié)構(gòu)體屬性中 我們可以通過(guò)加 tag 以供其他程序的解析與識(shí)別
package main import ( "fmt" "reflect" ) type resume struct { // ':'前后不加空格 ` != ' Name string `info:"name" doc:"我的名字" ` Sex string `info:"sex" ` } func findTag(str interface{}) { // Elem returns a type's element type. t := reflect.TypeOf(str).Elem() //遍歷接收對(duì)象的屬性 for i := 0; i < t.NumField(); i++ { taginfo := t.Field(i).Tag.Get("info") tagdoc := t.Field(i).Tag.Get("doc") fmt.Println("info:",taginfo,"doc:",tagdoc) } } func main() { var re resume findTag(&re) } 輸出: info: name doc: 我的名字 info: sex doc:
3.2 Json包的序列化與反序列化
go 的 json 工具要想解析 需要你在字段上添加 json tag
package main import ( "encoding/json" "fmt" ) // 全部添加 json 的 tag type Movie struct { Title string `json:"title"` Year int `json:"year"` Price int `json:"rmb"` Actors []string `json:"actors"` } func main() { movie := Movie{"喜劇之王", 2000, 10, []string{"zhouxingchi", "wumengda"}} // 序列化 jsonStr, err := json.Marshal(movie) if err != nil { fmt.Println("json marshal error",err) return } fmt.Printf("jsonStr = %s\n",jsonStr) //反序列化 m := Movie{} err = json.Unmarshal(jsonStr, &m) if err != nil { fmt.Println("json ummarshal error", err) return } fmt.Printf("%v\n",m) }
4. 實(shí)戰(zhàn)鞏固
4.1 需求
? 項(xiàng)目經(jīng)常會(huì)在啟動(dòng)的時(shí)候會(huì)加一些環(huán)境變量參數(shù),隨著啟動(dòng)而觸發(fā)作用加載到項(xiàng)目中,現(xiàn)如今在。利用os包設(shè)置好環(huán)境變量,利用反射實(shí)現(xiàn)項(xiàng)目啟動(dòng)時(shí)運(yùn)行時(shí)加載進(jìn)環(huán)境!
環(huán)境變量Key | CONFIG_SERVER_NAME | CONFIG_SERVER_IP | CONFIG_SERVER_URL |
---|
4.2 代碼實(shí)現(xiàn)
package main import ( "fmt" "os" "reflect" "strings" ) type Config struct { Name string `json:"server-name"` IP string `json:"server-ip"` URL string `json:"server-url"` Timeout string `json:"timeout"` } func readConfig() *Config { // read from xxx.json,省略 config := Config{} // 1. 拿到config的反射類型 typ := reflect.TypeOf(config) // 2. 拿到config的反射值對(duì)象 value := reflect.Indirect(reflect.ValueOf(&config)) // 3. 遍歷每個(gè)字段 for i := 0; i < typ.NumField(); i++ { // 3.1 拿到反射的config的第i個(gè)字段 f := typ.Field(i) // 3.2 拿到賦值了json的字段tag if v, ok := f.Tag.Lookup("json"); ok { // 3.3 拼接系統(tǒng)環(huán)境變量Key key := fmt.Sprintf("CONFIG_%s", strings.ReplaceAll(strings.ToUpper(v), "-", "_")) // 3.4 從系統(tǒng)中讀取環(huán)境變量對(duì)應(yīng)的值 if env, exist := os.LookupEnv(key); exist { // 3.5 將值設(shè)置到給定名稱的字段上 value.FieldByName(f.Name).Set(reflect.ValueOf(env)) } } } return &config } func main() { os.Setenv("CONFIG_SERVER_NAME", "global_server") os.Setenv("CONFIG_SERVER_IP", "10.0.0.1") os.Setenv("CONFIG_SERVER_URL", "geektutu.com") c := readConfig() fmt.Printf("%+v", c) }
到此這篇關(guān)于深入了解Golang中reflect反射的使用的文章就介紹到這了,更多相關(guān)Go reflect反射內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決golang時(shí)間字符串轉(zhuǎn)time.Time的坑
這篇文章主要介紹了解決golang時(shí)間字符串轉(zhuǎn)time.Time的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04Go語(yǔ)言kube-scheduler深度剖析開發(fā)之scheduler初始化
這篇文章主要介紹了Go語(yǔ)言kube-scheduler深度剖析開發(fā)之scheduler初始化實(shí)現(xiàn)過(guò)程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04golang如何通過(guò)type定義函數(shù)類型
這篇文章主要介紹了golang如何通過(guò)type定義函數(shù)類型問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01

Go語(yǔ)言轉(zhuǎn)換所有字符串為大寫或者小寫的方法

使用Golang實(shí)現(xiàn)對(duì)網(wǎng)絡(luò)數(shù)據(jù)包的捕獲與分析

詳解Go語(yǔ)言各種常見類型的默認(rèn)值和判空方法