1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        Golang反射-下篇

        共 2263字,需瀏覽 5分鐘

         ·

        2021-11-30 04:30

        目錄

        • 1、判斷類型 interface.Type

        • 2、自定義 struct 的反射

        • 3、結(jié)構(gòu)體標(biāo)簽和反射

        • 4、反射調(diào)用函數(shù)

        • 5、反射調(diào)用方法

        • 6、反射創(chuàng)建值

          • 6.1 反射創(chuàng)建 struct

          • 6.2 反射創(chuàng)建 slice

          • 6.3 反射創(chuàng)建 map

        • 7、反射修改值

          • 7.1 反射修改 struct

          • 7.2 反射修改 slice

          • 7.3 反射修改 map



        本文是?Golang反射-上篇 的續(xù)篇內(nèi)容,主要介紹反射實(shí)際的一些使用

        1、判斷類型 interface.Type

        利用類型斷言來判斷數(shù)據(jù)類型的用法如下

        package?main

        import?"fmt"

        func?main()??{
        ?var?s?interface{}?=?"abc"
        ?switch?s.(type)?{
        ?case?string:
        ??fmt.Println("s.type=string")
        ?case?int:
        ??fmt.Println("s.type=int")
        ?case?bool:
        ??fmt.Println("s.type=bool")
        ?default:
        ??fmt.Println("未知的類型")
        ?}
        }

        上述類型判斷的問題

        • 類型判斷會(huì)寫很多,代碼很長(zhǎng)
        • 類型還會(huì)增刪,不靈活

        如果使用反射獲取變量?jī)?nèi)部的信息

        • reflect 包提供 ValueOf 和 TypeOf
        • reflect.ValueOf:獲取輸入接口中數(shù)據(jù)的值,如果為空返回 0
        • reflect.TypeOf:獲取輸入接口中值的類型,如果為空返回 nil
        • TypeOf 能傳入所有類型,是因?yàn)樗械念愋投紝?shí)現(xiàn)了空接口
        package?main

        import?(
        ?"fmt"
        ?"reflect"
        )

        func?main()??{
        ?var?s?interface{}?=?"abc"
        ?//TypeOf會(huì)返回目標(biāo)的對(duì)象
        ?reflectType:=reflect.TypeOf(s)
        ?reflectValue:=reflect.ValueOf(s)
        ?fmt.Printf("[typeof:%v]\n",?reflectType)??//?string
        ?fmt.Printf("[valueof:%v]\n",?reflectValue)??//?abc
        }

        2、自定義 struct 的反射

        自定義 struct 的相關(guān)操作

        • 對(duì)于成員變量

          • 先獲取 interface 的 reflect.Type,然后遍歷 NumField
          • 再通過 reflect.Type 的 Field 獲取字段名及類型
          • 最后通過 Field 的 interface 獲取對(duì)應(yīng)的 value
        • 對(duì)于方法

          • 先獲取 interface 的 reflect.Type,然后遍歷 NumMethod
          • 再通過 reflect.Type 的 t.Method 獲取真實(shí)的方法名
          • 最后通過 Name 和 Type 獲取方法的類型和值

        注意點(diǎn)

        • 用于對(duì)未知類型進(jìn)行遍歷探測(cè)其 Field,抽象成一個(gè)函數(shù)
        • go 語言里面 struct 成員變量小寫,在反射的時(shí)候直接 panic()
        • 結(jié)構(gòu)體方法名小寫是不會(huì) panic 的,反射值也不會(huì)被查看到
        • 指針方法是不能被反射查看到的
        package?main

        import?(
        ?"fmt"
        ?"reflect"
        )

        type?Person?struct?{
        ?Name?string
        ?Age??int
        }

        type?Student?struct?{
        ?Person?????//?匿名結(jié)構(gòu)體嵌套
        ?StudentId??int
        ?SchoolName?string
        ?Graduated??bool
        ?Hobbies????[]string
        ?//panic:?reflect.Value.Interface:?cannot?return?value?obtained?from?unexported?field?or?method
        ?//hobbies????[]string
        ?Label??????map[string]string
        }

        func?(s?*Student)?GoHome()?{
        ?fmt.Printf("回家了,sid:%d\n",?s.StudentId)
        }

        //func?(s?Student)?GoHome()?{
        //?fmt.Printf("回家了,sid:%d\n",?s.StudentId)
        //}

        func?(s?Student)?GotoSchool()?{
        ?fmt.Printf("上學(xué)了,sid:%d\n",?s.StudentId)
        }

        func?(s?*Student)?graduated()?{
        ?fmt.Printf("畢業(yè)了,sid:%d\n",?s.StudentId)
        }

        //func?(s?Student)?Ggraduated()?{
        //?fmt.Printf("畢業(yè)了,sid:%d\n",?s.StudentId)
        //}

        func?reflectProbeStruct(s?interface{})?{
        ?//?獲取目標(biāo)對(duì)象
        ?t?:=?reflect.TypeOf(s)
        ?fmt.Printf("對(duì)象的類型名稱?%s\n",?t.Name())
        ?//?獲取目標(biāo)對(duì)象的值類型
        ?v?:=?reflect.ValueOf(s)
        ?//?遍歷獲取成員變量
        ?for?i?:=?0;?i???//?Field?代表對(duì)象的字段名
        ??key?:=?t.Field(i)
        ??value?:=?v.Field(i).Interface()
        ??//?字段
        ??if?key.Anonymous?{
        ???fmt.Printf("匿名字段?第?%d?個(gè)字段,字段名?%s,?字段類型?%v,?字段的值?%v\n",?i+1,?key.Name,?key.Type,?value)
        ??}?else?{
        ???fmt.Printf("命名字段?第?%d?個(gè)字段,字段名?%s,?字段類型?%v,?字段的值?%v\n",?i+1,?key.Name,?key.Type,?value)
        ??}
        ?}
        ?//?打印方法
        ?for?i?:=?0;?i???m?:=?t.Method(i)
        ??fmt.Printf("第?%d?個(gè)方法,方法名?%s,?方法類型?%v\n",?i+1,?m.Name,?m.Type)
        ?}
        }

        func?main()?{
        ?s?:=?Student{
        ??Person:?Person{
        ???"geek",
        ???24,
        ??},
        ??StudentId:??123,
        ??SchoolName:?"Beijing?University",
        ??Graduated:??true,
        ??Hobbies:????[]string{"唱",?"跳",?"Rap"},
        ??//hobbies:????[]string{"唱",?"跳",?"Rap"},
        ??Label:??????map[string]string{"k1":?"v1",?"k2":?"v2"},
        ?}
        ?p?:=?Person{
        ??Name:?"張三",
        ??Age:??100,
        ?}
        ?reflectProbeStruct(s)
        ?reflectProbeStruct(p)
        ?/*
        ?對(duì)象的類型名稱?Student
        ?匿名字段?第?1?個(gè)字段,字段名?Person,?字段類型?main.Person,?字段的值?{geek?24}
        ?命名字段?第?2?個(gè)字段,字段名?StudentId,?字段類型?int,?字段的值?123
        ?命名字段?第?3?個(gè)字段,字段名?SchoolName,?字段類型?string,?字段的值?Beijing?University
        ?命名字段?第?4?個(gè)字段,字段名?Graduated,?字段類型?bool,?字段的值?true
        ?命名字段?第?5?個(gè)字段,字段名?Hobbies,?字段類型?[]string,?字段的值?[唱?跳?Rap]
        ?命名字段?第?6?個(gè)字段,字段名?Label,?字段類型?map[string]string,?字段的值?map[k1:v1?k2:v2]
        ?第?1?個(gè)方法,方法名?GotoSchool,?方法類型?func(main.Student)
        ?對(duì)象的類型名稱?Person
        ?命名字段?第?1?個(gè)字段,字段名?Name,?字段類型?string,?字段的值?張三
        ?命名字段?第?2?個(gè)字段,字段名?Age,?字段類型?int,?字段的值?100
        ??*/

        }

        3、結(jié)構(gòu)體標(biāo)簽和反射

        • json 的標(biāo)簽解析出 json
        • yaml 的標(biāo)簽解析出 yaml
        • xorm、gorm 的標(biāo)簽標(biāo)識(shí)數(shù)據(jù)庫(kù) db 字段
        • 自定義標(biāo)簽
        • 原理是 t.Field.Tag.Lookup("標(biāo)簽名")

        示例

        package?main

        import?(
        ?"encoding/json"
        ?"fmt"
        ?"gopkg.in/yaml.v2"
        ?"io/ioutil"
        )

        type?Person?struct?{
        ?Name?string?`json:"name"?yaml:"yaml_name"`
        ?Age??int????`json:"age"?yaml:"yaml_age"`
        ?City?string?`json:"city"?yaml:"yaml_city"`
        ?//City?string?`json:"-"?yaml:"yaml_city"`?//?忽略json:"-"
        }

        //?json解析
        func?jsonWork()?{
        ?//?對(duì)象Marshal成字符串
        ?p?:=?Person{
        ??Name:?"geek",
        ??Age:??24,
        ??City:?"Beijing",
        ?}
        ?data,?err?:=?json.Marshal(p)
        ?if?err?!=?nil?{
        ??fmt.Printf("json.marshal.err:?%v\n",?err)
        ?}
        ?fmt.Printf("person.marshal.res:?%v\n",?string(data))

        ?//?從字符串解析成結(jié)構(gòu)體
        ?p2str?:=?`{
        ?"name":?"張三",
        ?"age":?38,
        ?"city":?"山東"
        ?}`

        ?var?p2?Person
        ?err?=?json.Unmarshal([]byte(p2str),?&p2)
        ?if?err?!=?nil?{
        ??fmt.Printf("json.unmarshal.err:?%v\n",?err)
        ??return
        ?}
        ?fmt.Printf("person.unmarshal.res:?%v\n",?p2)
        }

        //?yaml解析
        func?yamlWork()?{
        ?filename?:=?"a.yaml"
        ?content,?err?:=?ioutil.ReadFile(filename)
        ?if?err?!=?nil?{
        ??fmt.Printf("ioutil.ReadFile.err:?%v\n",?err)
        ??return
        ?}
        ?p?:=?&Person{}
        ?//err?=?yaml.Unmarshal([]byte(content),?p)
        ?err?=?yaml.UnmarshalStrict([]byte(content),?p)??//?解析嚴(yán)格,考慮多余字段,忽略字段等
        ?if?err?!=?nil?{
        ??fmt.Printf("yaml.UnmarshalStrict.err:?%v\n",?err)
        ??return
        ?}
        ?fmt.Printf("yaml.UnmarshalStrict.res:?%v\n",?p)
        }

        func?main()?{
        ?jsonWork()
        ?/*
        ??person.marshal.res:?{"name":"geek","age":24,"city":"Beijing"}
        ??person.unmarshal.res:?{張三?38?山東}
        ?*/

        ?yamlWork()
        ?/*
        ??yaml.UnmarshalStrict.res:?&{李四?18?Shanghai}
        ??*/

        }

        解析的 yaml 內(nèi)容

        yaml_name:?李四
        yaml_age:?18
        yaml_city:?Shanghai
        • 自定義標(biāo)簽格式解析
        package?main

        import?(
        ?"fmt"
        ?"reflect"
        )

        type?Person?struct?{
        ?Name?string?`aa:"name"`
        ?Age??int????`aa:"age"`
        ?City?string?`aa:"city"`
        }

        //?CustomParse?自定義解析
        func?CustomParse(s?interface{})?{
        ?//?TypeOf?type類型
        ?r:=reflect.TypeOf(s)
        ?value?:=?reflect.ValueOf(s)
        ?for?i:=0;i??field:=r.Field(i)
        ??key:=field.Name
        ??if?tag,?ok:=field.Tag.Lookup("aa");ok{
        ???if?tag?==?"-"{
        ????continue
        ???}
        ???fmt.Printf("找到了aa標(biāo)簽,?key:?%v,?value:?%v,?tag:?%s\n",?key,?value.Field(i),?tag)
        ??}
        ?}
        }

        func?main()?{
        ?p?:=?Person{
        ??Name:?"geek",
        ??Age:??24,
        ??City:?"Beijing",
        ?}
        ?CustomParse(p)
        ?/*
        ?找到了aa標(biāo)簽,?key:?Name,?value:?geek,?tag:?name
        ?找到了aa標(biāo)簽,?key:?Age,?value:?24,?tag:?age
        ?找到了aa標(biāo)簽,?key:?City,?value:?Beijing,?tag:?city
        ??*/

        }

        4、反射調(diào)用函數(shù)

        valueFunc?:=?reflect.ValueOf(Add)?//函數(shù)也是一種數(shù)據(jù)類型
        typeFunc?:=?reflect.TypeOf(Add)
        argNum?:=?typeFunc.NumIn()????????????//函數(shù)輸入?yún)?shù)的個(gè)數(shù)
        args?:=?make([]reflect.Value,?argNum)?//準(zhǔn)備函數(shù)的輸入?yún)?shù)
        for?i?:=?0;?i??if?typeFunc.In(i).Kind()?==?reflect.Int?{
        ??args[i]?=?reflect.ValueOf(3)?//給每一個(gè)參數(shù)都賦3
        ?}
        }
        sumValue?:=?valueFunc.Call(args)?//返回[]reflect.Value,因?yàn)間o語言的函數(shù)返回可能是一個(gè)列表
        if?typeFunc.Out(0).Kind()?==?reflect.Int?{
        ?sum?:=?sumValue[0].Interface().(int)?//從Value轉(zhuǎn)為原始數(shù)據(jù)類型
        ?fmt.Printf("sum=%d\n",?sum)
        }

        5、反射調(diào)用方法

        示例

        user?:=?User{
        ?Id:?????7,
        ?Name:???"杰克遜",
        ?Weight:?65.5,
        ?Height:?1.68,
        }
        valueUser?:=?reflect.ValueOf(&user)??????????????//必須傳指針,因?yàn)锽MI()在定義的時(shí)候它是指針的方法
        bmiMethod?:=?valueUser.MethodByName("BMI")???????//MethodByName()通過Name返回類的成員變量
        resultValue?:=?bmiMethod.Call([]reflect.Value{})?//無參數(shù)時(shí)傳一個(gè)空的切片
        result?:=?resultValue[0].Interface().(float32)
        fmt.Printf("bmi=%.2f\n",?result)

        //Think()在定義的時(shí)候用的不是指針,valueUser可以用指針也可以不用指針
        thinkMethod?:=?valueUser.MethodByName("Think")
        thinkMethod.Call([]reflect.Value{})

        valueUser2?:=?reflect.ValueOf(user)
        thinkMethod?=?valueUser2.MethodByName("Think")
        thinkMethod.Call([]reflect.Value{})

        過程

        • 首先通過 reflect.ValueOf(p1) 獲取得到反射類型對(duì)象
        • reflect.ValueOf(p1).MethodByName 需 要傳入準(zhǔn)確的方法名稱(名稱不對(duì)會(huì) panic: reflect: call of reflect.Value.Call on zero Value),MethodByName 代表注冊(cè)
        • []reflect.Value 這是最終需要調(diào)用方法的參數(shù),無參數(shù)傳空切片
        • call 調(diào)用
        package?main

        import?(
        ?"fmt"
        ?"reflect"
        )

        type?Person?struct?{
        ?Name???string
        ?Age????int
        ?Gender?string
        }

        func?(p?Person)?ReflectCallFuncWithArgs(name?string,?age?int)?{
        ?fmt.Printf("調(diào)用的是帶參數(shù)的方法,?args.name:?%s,?args.age:?%d,?p.name:?%s,?p.age:?%d\n",
        ??name,
        ??age,
        ??p.Name,
        ??p.Age,
        ?)
        }

        func?(p?Person)?ReflectCallFuncWithNoArgs()?{
        ?fmt.Printf("調(diào)用的是不帶參數(shù)的方法\n")
        }

        func?main()?{
        ?p1?:=?Person{
        ??Name:???"geek",
        ??Age:????24,
        ??Gender:?"男",
        ?}
        ?//?1.首先通過reflect.ValueOf(p1)獲取得到反射值類型
        ?getValue?:=?reflect.ValueOf(p1)
        ?//?2.帶參數(shù)的方法調(diào)用
        ?methodValue1?:=?getValue.MethodByName("ReflectCallFuncWithArgs")
        ?//?參數(shù)是reflect.Value的切片
        ?args1?:=?[]reflect.Value{reflect.ValueOf("張三"),?reflect.ValueOf(30)}
        ?methodValue1.Call(args1)
        ?//?3.不帶參數(shù)的方法調(diào)用
        ?methodValue2?:=?getValue.MethodByName("ReflectCallFuncWithNoArgs")
        ?//?參數(shù)是reflect.Value的切片
        ?args2?:=?make([]reflect.Value,?0)
        ?methodValue2.Call(args2)
        ?/*
        ?調(diào)用的是帶參數(shù)的方法,?args.name:?張三,?args.age:?30,?p.name:?geek,?p.age:?24
        ?調(diào)用的是不帶參數(shù)的方法
        ??*/

        }

        6、反射創(chuàng)建值

        6.1 反射創(chuàng)建 struct

        t?:=?reflect.TypeOf(User{})
        value?:=?reflect.New(t)?//根據(jù)reflect.Type創(chuàng)建一個(gè)對(duì)象,得到該對(duì)象的指針,再根據(jù)指針提到reflect.Value
        value.Elem().FieldByName("Id").SetInt(10)
        value.Elem().FieldByName("Name").SetString("宋江")
        value.Elem().FieldByName("Weight").SetFloat(78.)
        value.Elem().FieldByName("Height").SetFloat(168.4)
        user?:=?value.Interface().(*User)?//把反射類型轉(zhuǎn)成go原始數(shù)據(jù)類型
        fmt.Printf("id=%d?name=%s?weight=%.1f?height=%.1f\n",?user.Id,?user.Name,?user.Weight,?user.Height)

        6.2 反射創(chuàng)建 slice

        var?slice?[]User
        sliceType?:=?reflect.TypeOf(slice)
        sliceValue?:=?reflect.MakeSlice(sliceType,?1,?3)?//reflect.MakeMap、reflect.MakeSlice、reflect.MakeChan、reflect.MakeFunc
        sliceValue.Index(0).Set(reflect.ValueOf(User{
        ?Id:?????8,
        ?Name:???"李達(dá)",
        ?Weight:?80,
        ?Height:?180,
        }))
        users?:=?sliceValue.Interface().([]User)
        fmt.Printf("1st?user?name?%s\n",?users[0].Name)

        6.3 反射創(chuàng)建 map

        var?userMap?map[int]*User
        mapType?:=?reflect.TypeOf(userMap)
        //?mapValue:=reflect.MakeMap(mapType)
        mapValue?:=?reflect.MakeMapWithSize(mapType,?10)?//reflect.MakeMap、reflect.MakeSlice、reflect.MakeChan、reflect.MakeFunc

        user?:=?&common.User{
        ?Id:?????7,
        ?Name:???"杰克遜",
        ?Weight:?65.5,
        ?Height:?1.68,
        }
        key?:=?reflect.ValueOf(user.Id)
        mapValue.SetMapIndex(key,?reflect.ValueOf(user))????????????????????//SetMapIndex?往map里添加一個(gè)key-value對(duì)
        mapValue.MapIndex(key).Elem().FieldByName("Name").SetString("令狐一刀")?//MapIndex?根據(jù)Key取出對(duì)應(yīng)的map
        userMap?=?mapValue.Interface().(map[int]*User)
        fmt.Printf("user?name?%s?%s\n",?userMap[7].Name,?user.Name)

        7、反射修改值

        反射修改值要求必須是指針類型

        修改值的操作:pointer.Elem().Setxxx()

        package?main

        import?(
        ?"fmt"
        ?"reflect"
        )

        func?main()?{
        ?var?num?float64?=?3.14
        ?fmt.Printf("原始值?%f\n",?num)
        ?//?通過reflect.ValueOf獲取num中的value,必須是指針才可以修改值
        ?//pointer?:=?reflect.ValueOf(num)??//?直接傳值會(huì)panic
        ?pointer?:=?reflect.ValueOf(&num)
        ?newValue?:=?pointer.Elem()
        ?//?賦新的值
        ?newValue.SetFloat(5.66)
        ?fmt.Printf("新的值?%f\n",?num)
        }

        7.1 反射修改 struct

        user?:=?User{
        ?Id:?????7,
        ?Name:???"杰克遜",
        ?Weight:?65.5,
        ?Height:?1.68,
        }
        valueUser?:=?reflect.ValueOf(&user)
        //?valueS.Elem().SetInt(8)//會(huì)panic
        valueUser.Elem().FieldByName("Weight").SetFloat(68.0)?//FieldByName()通過Name返回類的成員變量。不能在指針Value上調(diào)用FieldByName
        addrValue?:=?valueUser.Elem().FieldByName("addr")
        if?addrValue.CanSet()?{
        ?addrValue.SetString("北京")
        }?else?{
        ?fmt.Println("addr是未導(dǎo)出成員,不可Set")?//以小寫字母開頭的成員相當(dāng)于是私有成員
        }

        7.2 反射修改 slice

        下面示例,間接的實(shí)現(xiàn)了 append 功能

        users?:=?make([]*User,?1,?5)?//len=1,cap=5

        sliceValue?:=?reflect.ValueOf(&users)?//準(zhǔn)備通過Value修改users,所以傳users的地址
        if?sliceValue.Elem().Len()?>?0?{??????//取得slice的長(zhǎng)度
        ?sliceValue.Elem().Index(0).Elem().FieldByName("Name").SetString("哈哈哈")
        ?//?u0?:=?users[0]
        ?fmt.Printf("1st?user?name?change?to?%s\n",?users[0].Name)
        }

        sliceValue.Elem().SetCap(3)?//新的cap必須位于原始的len到cap之間
        sliceValue.Elem().SetLen(2)
        //調(diào)用reflect.Value的Set()函數(shù)修改其底層指向的原始數(shù)據(jù)
        sliceValue.Elem().Index(1).Set(reflect.ValueOf(&User{
        ?Id:?????8,
        ?Name:???"geek",
        ?Weight:?80,
        ?Height:?180,
        }))
        fmt.Printf("2nd?user?name?%s\n",?users[1].Name)

        7.3 反射修改 map

        u1?:=?&User{
        ?Id:?????7,
        ?Name:???"杰克遜",
        ?Weight:?65.5,
        ?Height:?1.68,
        }
        u2?:=?&User{
        ?Id:?????8,
        ?Name:???"杰克遜",
        ?Weight:?65.5,
        ?Height:?1.68,
        }
        userMap?:=?make(map[int]*User,?5)
        userMap[u1.Id]?=?u1

        mapValue?:=?reflect.ValueOf(&userMap)?????????????????????????????????????????????????????????//準(zhǔn)備通過Value修改userMap,所以傳userMap的地址
        mapValue.Elem().SetMapIndex(reflect.ValueOf(u2.Id),?reflect.ValueOf(u2))??????????????????????//SetMapIndex?往map里添加一個(gè)key-value對(duì)
        mapValue.Elem().MapIndex(reflect.ValueOf(u1.Id)).Elem().FieldByName("Name").SetString("令狐一刀")?//MapIndex?根據(jù)Key取出對(duì)應(yīng)的map
        for?k,?user?:=?range?userMap?{
        ?fmt.Printf("key?%d?name?%s\n",?k,?user.Name)
        }

        See you ~

        歡迎進(jìn)群一起進(jìn)行技術(shù)交流

        加群方式:公眾號(hào)消息私信“加群或加我好友再加群均可

        瀏覽 110
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日日撸天天干 | 看男人操女人逼 | 污的网站在线观看豆花视频 | 亚洲日韩国产第一页 | 公和我乱做好爽添厨房 | 亚洲高清超级无码在线视频观看 | 国产小电影在线观看 | 小h短篇辣肉各种姿势老师 | 欧美日韩十八禁 | 免费看黄30分钟 |