<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] ### 反射是什么 反射是指在程序運行期對程序本身進行訪問和修改的能力。程序在編譯時,變量被轉換為內存地址,變量名不會被編譯器寫入到可執行部分。在運行程序時,程序無法獲取自身的信息。 ### 反射的三大定律 * 反射可以將“接口類型變量”轉換為“反射類型對象”; * 反射可以將“反射類型對象”轉換為“接口類型變量”; * 如果要修改“反射類型對象”,其值必須是“可寫的”(settable)。 ### 用法 #### reflect.TypeOf() ``` func TypeOf(i interface{}) Type ``` 在反射中關于類型還劃分為兩種:`類型(Type)`和`種類(Kind)` `類型(Type)`:就是自己定義的類型 `種類(Kind)`:指底層的類型 ~~~ type newInt int func main() { var testNum newInt = 10 typeOfTestNum := reflect.TypeOf(testNum) fmt.Println(typeOfTestNum) //main.newInt //獲取類型 fmt.Println(typeOfTestNum.Name()) //newInt //獲取種類,即底層數據類型 fmt.Println(typeOfTestNum.Kind()) //int fmt.Println(reflect.ValueOf(testNum)) //10 } ~~~ Go語言的反射中像數組、切片、Map、指針等類型的變量,它們的`.Name()`都是返回`空`。 #### reflect.ValueOf() ``` func ValueOf(i interface{}) Value ``` 使用reflect.ValueOf() 獲取的值的類型是`reflect.Value`類型,其中包含了原始值的值信息。 可以進行轉化 | 方法 | 說明 | | --- | --- | | Interface() interface {} | 將值以 interface{} 類型返回,可以通過類型斷言轉換為指定類型 | | Int() int64 | 將值以 int 類型返回,所有有符號整型均可以此方式返回 | | Uint() uint64 | 將值以 uint 類型返回,所有無符號整型均可以此方式返回 | | Float() float64 | 將值以雙精度(float64)類型返回,所有浮點數(float32、float64)均可以此方式返回 | | Bool() bool | 將值以 bool 類型返回 | | Bytes() \[\]bytes | 將值以字節數組 \[\]bytes 類型返回 | | String() string | 將值以字符串類型返回 | ~~~go func reflectValue(x interface{}) { v := reflect.ValueOf(x) k := v.Kind() switch k { case reflect.Int64: // v.Int()從反射中獲取整型的原始值,然后通過int64()強制類型轉換 fmt.Printf("type is int64, value is %d\n", int64(v.Int())) case reflect.Float32: // v.Float()從反射中獲取浮點型的原始值,然后通過float32()強制類型轉換 fmt.Printf("type is float32, value is %f\n", float32(v.Float())) case reflect.Float64: // v.Float()從反射中獲取浮點型的原始值,然后通過float64()強制類型轉換 fmt.Printf("type is float64, value is %f\n", float64(v.Float())) } } func main() { var a float32 = 3.14 var b int64 = 100 reflectValue(a) // type is float32, value is 3.140000 reflectValue(b) // type is int64, value is 100 // 將int類型的原始值轉換為reflect.Value類型 c := reflect.ValueOf(10) fmt.Printf("type c :%T\n", c) // type c :reflect.Value } ~~~ ### isNil()和isValid() #### isNil() 常被用于判斷指針是否為空 ~~~go func (v Value) IsNil() bool ~~~ `IsNil()`報告v持有的值是否為nil。v持有的值的分類必須是通道、函數、接口、映射、指針、切片之一;否則IsNil函數會導致panic。 #### isValid() 常被用于判定返回值是否有效 ~~~go func (v Value) IsValid() bool ~~~ `IsValid()`返回v是否持有一個值。如果v是Value零值會返回假,此時v除了IsValid、String、Kind之外的方法都會導致panic。 ~~~ func main() { var testNum int = 10 ptrOfTestNum := &testNum valueOfTestNum := reflect.ValueOf(ptrOfTestNum) fmt.Println(valueOfTestNum.IsNil()) // false fmt.Println(valueOfTestNum.IsValid()) //true } ~~~ #### 修改反射值 使用反射進行值屬性獲取或修改值前,**一定要確保操作對象是可尋址的**。對于修改值得操作,還要**確保操作對象是可被修改的**。Go 語言提供了相應的方法幫助我們進行判斷,分別是 CanAddr() 和 CanSet(); ~~~ func main() { var testNum int = 10 ptrOfTestNum := &testNum valueOfPtrTestNum := reflect.ValueOf(ptrOfTestNum) fmt.Println(valueOfPtrTestNum.Elem().CanAddr()) fmt.Println(valueOfPtrTestNum.Elem().CanSet()) valueOfPtrTestNum.Elem().SetInt(20) } ~~~ **Elem() 函數的作用是返回指針指向的數據** 注意:使用 Elem() 函數時,若作用于非指針或接口時,將引發宕機。作用于空指針時,將返回 nil。 ~~~ func (v Value) Elem() Value { k := v.kind() switch k { case Interface: var eface interface{} if v.typ.NumMethod() == 0 { eface = *(*interface{})(v.ptr) } else { eface = (interface{})(*(*interface { M() })(v.ptr)) } x := unpackEface(eface) if x.flag != 0 { x.flag |= v.flag.ro() } return x case Ptr: ptr := v.ptr if v.flag&flagIndir != 0 { ptr = *(*unsafe.Pointer)(ptr) } // The returned value's address is v's value. if ptr == nil { return Value{} } tt := (*ptrType)(unsafe.Pointer(v.typ)) typ := tt.elem fl := v.flag&flagRO | flagIndir | flagAddr fl |= flag(typ.Kind()) return Value{typ, ptr, fl} } panic(&ValueError{"reflect.Value.Elem", v.kind()}) } ~~~ ### 結構體反射 `reflect.Type`中與獲取結構體成員相關的的方法如下表所示。 | 方法 | 說明 | | --- | --- | | Field(i int) StructField | 根據索引,返回索引對應的結構體字段的信息。 | | NumField() int | 返回結構體成員字段數量。 | | FieldByName(name string) (StructField, bool) | 根據給定字符串返回字符串對應的結構體字段的信息。 | | FieldByIndex(index \[\]int) StructField | 多層成員訪問時,根據 \[\]int 提供的每個結構體的字段索引,返回字段的信息。 | | FieldByNameFunc(match func(string) bool) (StructField,bool) | 根據傳入的匹配函數匹配需要的字段。 | | NumMethod() int | 返回該類型的方法集中方法的數目 | | Method(int) Method | 返回該類型方法集中的第i個方法 | | MethodByName(string)(Method, bool) | 根據方法名返回該類型方法集中的方法 | ~~~ rt := reflect.TypeOf(&Teacher{}) fmt.Println(rt.NumMethod(), rt.Method(0).Name) for i := 0; i < rt.NumField(); i++ { s := rt.Field(i) fmt.Println(s, s.Name, s.Type, s.Tag)//獲取所有的tag,獲取單個tag,Tag.Get(“json”) } rt1 := reflect.ValueOf(T1{Name: "hahha", Age: 55}) for i := 0; i < rt1.NumField(); i++ { //s1 := rt.Field(i) s := rt1.Field(i) //fmt.Println(s1.Name, s) fmt.Println(s) //hahha 55 } ~~~ ### 使用反射調用函數 ~~~ func addCalc(num1 int, num2 int) int { return num1 + num2 } func main() { ret := reflect.TypeOf(addCalc) fmt.Println(ret) //func(int, int) int ret1 := reflect.ValueOf(addCalc) fmt.Println(ret1) //0xe39da0 //用call調用,并傳參,參數類型是reflect.Value res := ret1.Call([]reflect.Value{reflect.ValueOf(10), reflect.ValueOf(10)}) fmt.Println(res[0]) } ~~~ ### 使用反射創建實例 通過反射創建實例,通常**用于創建一個與已知變量同類型的變量**。如此創建的**變量類型只有在程序運行時才會被確定,更加靈活多變**。 舉例來說,現有一個變量 num,它的類型是自定義的 myInt 類型。我們若想創建與其相同類型的變量,方法如下: ~~~go type myInt int func main() { var num myInt = 100 typeOfNum := reflect.TypeOf(num) anotherNum := reflect.New(typeOfNum) anotherNum.Elem().SetInt(300) fmt.Println(num) fmt.Println(anotherNum.Type(), anotherNum.Type().Kind()) fmt.Println(anotherNum.Elem().Int()) } ~~~ 使用反射創建變量,核心在于**reflect.New() 函數。該函數接收 reflect.Type 類型參數,返回 reflect.Value 類型值**。該值是一個指針,本例中的 anotherNum 類型實際上是 \*main.myInt,從種類上講是 ptr。 運行這段代碼,控制臺輸出如下: > 100 > *main.myInt ptr > 300
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看