一篇文章教會你Go語言基礎之結構體反射
前言
Hey,大家好呀,我是碼農,星期八。
反射在結構體中的應用,才是最廣泛的!畢竟在Go中,是用結構體代替對象的!
所以最多的,最麻煩的,也是反射結構體,也是最靈活的!
反射在結構體的應用
上次講的,只是在普通變量中的應用,相對來說,使用的場景不是太多。
但是反射在結構體中的應用,基本會貫穿整個Go語言基礎。
示例代碼
結構體
- 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() {
- //實例化結構體
- 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()) //結果:4,表示多少個字段
- for i := 0; i < t.NumField(); i++ {
- field := t.Field(i)//每個結構體對象
- /*
- {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"))
- }
- }
執行結果

單獨反射指定字段信息
main代碼
- func main() {
- //實例化結構體
- 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() {
- //實例化結構體
- 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())
- }
- }
執行結果
反射方法
上述我們反射的都是值,有沒有反射是否可以反射函數,并且調用函數呢??
結構體和綁定函數代碼
- 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)
- }
- //有參數方法
- func (this Student) Jump(distance int) {
- fmt.Printf("我是%v,我跳遠跳了%v米\n", this.Name, distance)
- }
main
- func main() {
- //實例化結構體
- 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 函數地址
- fmt.Println(method.Type())//func(int) 函數類型,形參和返回值
- fmt.Println(t.Method(i).Name)//Jump,函數名,注意,由t來調用的
- }
- }
執行結果
反射調用函數
- func main() {
- //實例化結構體
- var s1 = Student{
- Name: "張三",
- Age: 18,
- Gender: true,
- Hobby: []string{"吃", "喝", "pia", "玩"},
- }
- var v = reflect.ValueOf(s1)
- //通過反射調用函數
- //調用Jump函數
- //反射調用函數必須傳一個參數,不管有沒有形參都要傳
- //var args = []reflect.Value{}
- //v.MethodByName("Say").Call(args)
- //如果需要傳參數
- //參數需要用reflect.ValueOf(1) 強轉一下
- var args = []reflect.Value{reflect.ValueOf(2)}
- v.MethodByName("Jump").Call(args)
- }
注:注意第14行和20行代碼區別,如果要傳參數,參考第20行代碼。
執行結果

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