一篇文章教會你Go語言基礎(chǔ)之結(jié)構(gòu)體反射
前言
Hey,大家好呀,我是碼農(nóng),星期八。
反射在結(jié)構(gòu)體中的應(yīng)用,才是最廣泛的!畢竟在Go中,是用結(jié)構(gòu)體代替對象的!
所以最多的,最麻煩的,也是反射結(jié)構(gòu)體,也是最靈活的!
反射在結(jié)構(gòu)體的應(yīng)用
上次講的,只是在普通變量中的應(yīng)用,相對來說,使用的場景不是太多。
但是反射在結(jié)構(gòu)體中的應(yīng)用,基本會貫穿整個Go語言基礎(chǔ)。
示例代碼
結(jié)構(gòu)體
- type Student struct {
- Name string `json:"name" describe:"姓名"`
- Age int `json:"age" describe:"年齡"`
- Gender bool `json:"gender" describe:"性別"`
- Hobby []string `json:"hobby" describe:"愛好"`
- }
main
- func main() {
- //實例化結(jié)構(gòu)體
- var s1 = Student{
- Name: "張三",
- Age: 18,
- Gender: true,
- Hobby: []string{"吃", "喝", "pia", "玩"},
- }
- var t = reflect.TypeOf(s1)
- fmt.Println(t.Name()) //Student
- fmt.Println(t.Kind()) //struct
- fmt.Println(t.NumField()) //結(jié)果:4,表示多少個字段
- for i := 0; i < t.NumField(); i++ {
- field := t.Field(i)//每個結(jié)構(gòu)體對象
- /*
- {Name string json:"name" describe:"姓名" 0 [0] false}
- {Age int json:"age" describe:"年齡" 16 [1] false}
- {Gender bool json:"gender" describe:"性別" 24 [2] false}
- {Hobby []string json:"hobby" describe:"愛好" 32 [3] false}
- */
- //fmt.Println(field)
- fmt.Println("------")
- fmt.Printf("field.Name:%v\n",field.Name)
- fmt.Printf("field.Index:%v\n",field.Index)
- fmt.Printf("field.Type:%v\n",field.Type)
- fmt.Printf("field.Tag:%v\n",field.Tag.Get("describe"))
- }
- }
執(zhí)行結(jié)果

單獨反射指定字段信息
main代碼
- func main() {
- //實例化結(jié)構(gòu)體
- var s1 = Student{
- Name: "張三",
- Age: 18,
- Gender: true,
- Hobby: []string{"吃", "喝", "pia", "玩"},
- }
- var t = reflect.TypeOf(s1)
- genderField, ok := t.FieldByName("Gender")
- if ok {
- fmt.Println(genderField.Name) //Gender
- fmt.Println(genderField.Index) //[2]
- fmt.Println(genderField.Type) //bool
- fmt.Println(genderField.Tag.Get("describe")) //性別
- }
- }
ValueOf
上述的代碼只能用的是TypeOf,只能返回類型等信息,相對來說不是太智能,ValueOf可以獲取值,同樣也能獲取類型,相對來說比TypeOf好一點。
示例代碼
main
- func main() {
- //實例化結(jié)構(gòu)體
- var s1 = Student{
- Name: "張三",
- Age: 18,
- Gender: true,
- Hobby: []string{"吃", "喝", "pia", "玩"},
- }
- var v = reflect.ValueOf(s1)
- for i := 0; i < v.NumField(); i++ {
- field :=v.Field(i)
- fmt.Println("------")
- fmt.Printf("Kind:%v\n",field.Kind())
- fmt.Printf("值:%v\n",field.Interface())
- }
- }
執(zhí)行結(jié)果
反射方法
上述我們反射的都是值,有沒有反射是否可以反射函數(shù),并且調(diào)用函數(shù)呢??
結(jié)構(gòu)體和綁定函數(shù)代碼
- type Student struct {
- Name string `json:"name" describe:"姓名"`
- Age int `json:"age" describe:"年齡"`
- Gender bool `json:"gender" describe:"性別"`
- Hobby []string `json:"hobby" describe:"愛好"`
- }
- //無參方法
- func (this Student) Say() {
- fmt.Printf("我是%v,我的年齡是%v,我的性別是%v,我的愛好是%v\n", this.Name, this.Age, this.Gender, this.Hobby)
- }
- //有參數(shù)方法
- func (this Student) Jump(distance int) {
- fmt.Printf("我是%v,我跳遠(yuǎn)跳了%v米\n", this.Name, distance)
- }
main
- func main() {
- //實例化結(jié)構(gòu)體
- var s1 = Student{
- Name: "張三",
- Age: 18,
- Gender: true,
- Hobby: []string{"吃", "喝", "pia", "玩"},
- }
- var t = reflect.TypeOf(s1)
- var v = reflect.ValueOf(s1)
- fmt.Println(v.NumMethod(),v.NumField())
- for i := 0; i < v.NumMethod(); i++ {
- method := v.Method(i)
- fmt.Println("--------")
- fmt.Println(method)//0x48c4e0 函數(shù)地址
- fmt.Println(method.Type())//func(int) 函數(shù)類型,形參和返回值
- fmt.Println(t.Method(i).Name)//Jump,函數(shù)名,注意,由t來調(diào)用的
- }
- }
執(zhí)行結(jié)果
反射調(diào)用函數(shù)
- func main() {
- //實例化結(jié)構(gòu)體
- var s1 = Student{
- Name: "張三",
- Age: 18,
- Gender: true,
- Hobby: []string{"吃", "喝", "pia", "玩"},
- }
- var v = reflect.ValueOf(s1)
- //通過反射調(diào)用函數(shù)
- //調(diào)用Jump函數(shù)
- //反射調(diào)用函數(shù)必須傳一個參數(shù),不管有沒有形參都要傳
- //var args = []reflect.Value{}
- //v.MethodByName("Say").Call(args)
- //如果需要傳參數(shù)
- //參數(shù)需要用reflect.ValueOf(1) 強(qiáng)轉(zhuǎn)一下
- var args = []reflect.Value{reflect.ValueOf(2)}
- v.MethodByName("Jump").Call(args)
- }
注:注意第14行和20行代碼區(qū)別,如果要傳參數(shù),參考第20行代碼。
執(zhí)行結(jié)果

反射注意事項
在平常開發(fā)中,盡量慎用反射,原因如下。
- 反射性能可能會比較低,畢竟是反正走的,一般比正向操作慢一兩個級別。
- 反射越多,代碼越爛,TypeOf和ValueOf都有Kind,很多情況是TypeOf和ValueOf混用的,所以對于基礎(chǔ)不好的,極不友好。
- 在Go中,是沒有try的,如果反射沒有處理好異常,程序會直接崩潰,可能在意想不到的地方。
總結(jié)
上述我們主要講述了Go反射結(jié)構(gòu)體的相關(guān)知識,包括有
- 反射在結(jié)構(gòu)體中的應(yīng)用
- 如何單獨反射結(jié)構(gòu)體字段信息
- ValueOf其他操作
- 如何放射結(jié)構(gòu)體綁定的方法
到此為止反射就講完了,一定要多嘗試,多敲敲代碼,反射的用法還有很多。