日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
創(chuàng)新互聯(lián)GO教程:Go語(yǔ)言通過(guò)反射修改變量的值

Go語(yǔ)言中類似 x、x.f[1] 和 *p 形式的表達(dá)式都可以表示變量,但是其它如 x + 1 和 f(2) 則不是變量。一個(gè)變量就是一個(gè)可尋址的內(nèi)存空間,里面存儲(chǔ)了一個(gè)值,并且存儲(chǔ)的值可以通過(guò)內(nèi)存地址來(lái)更新。

創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括從江網(wǎng)站建設(shè)、從江網(wǎng)站制作、從江網(wǎng)頁(yè)制作以及從江網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,從江網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到從江省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

對(duì)于 reflect.Values 也有類似的區(qū)別。有一些 reflect.Values 是可取地址的;其它一些則不可以。考慮以下的聲明語(yǔ)句:

x := 2 // value type variable?
a := reflect.ValueOf(2) // 2 int no
b := reflect.ValueOf(x) // 2 int no
c := reflect.ValueOf(&x) // &x *int no
d := c.Elem() // 2 int yes (x)

其中 a 對(duì)應(yīng)的變量則不可取地址。因?yàn)?a 中的值僅僅是整數(shù) 2 的拷貝副本。b 中的值也同樣不可取地址。c 中的值還是不可取地址,它只是一個(gè)指針 &x 的拷貝。實(shí)際上,所有通過(guò) reflect.ValueOf(x) 返回的 reflect.Value 都是不可取地址的。但是對(duì)于 d,它是 c 的解引用方式生成的,指向另一個(gè)變量,因此是可取地址的。我們可以通過(guò)調(diào)用 reflect.ValueOf(&x).Elem(),來(lái)獲取任意變量x對(duì)應(yīng)的可取地址的 Value。

我們可以通過(guò)調(diào)用 reflect.Value 的 CanAddr 方法來(lái)判斷其是否可以被取地址:

fmt.Println(a.CanAddr()) // "false"
fmt.Println(b.CanAddr()) // "false"
fmt.Println(c.CanAddr()) // "false"
fmt.Println(d.CanAddr()) // "true"

每當(dāng)我們通過(guò)指針間接地獲取的 reflect.Value 都是可取地址的,即使開(kāi)始的是一個(gè)不可取地址的 Value。在反射機(jī)制中,所有關(guān)于是否支持取地址的規(guī)則都是類似的。例如,slice 的索引表達(dá)式 e[i]將隱式地包含一個(gè)指針,它就是可取地址的,即使開(kāi)始的e表達(dá)式不支持也沒(méi)有關(guān)系。

以此類推,reflect.ValueOf(e).Index(i) 對(duì)于的值也是可取地址的,即使原始的 reflect.ValueOf(e) 不支持也沒(méi)有關(guān)系。

使用 reflect.Value 對(duì)包裝的值進(jìn)行修改時(shí),需要遵循一些規(guī)則。如果沒(méi)有按照規(guī)則進(jìn)行代碼設(shè)計(jì)和編寫(xiě),輕則無(wú)法修改對(duì)象值,重則程序在運(yùn)行時(shí)會(huì)發(fā)生宕機(jī)。

判定及獲取元素的相關(guān)方法

使用 reflect.Value 取元素、取地址及修改值的屬性方法請(qǐng)參考下表。

反射值對(duì)象的判定及獲取元素的方法

方法名 備  注
Elem() Value 取值指向的元素值,類似于語(yǔ)言層*操作。當(dāng)值類型不是指針或接口時(shí)發(fā)生宕 機(jī),空指針時(shí)返回 nil 的 Value
Addr() Value 對(duì)可尋址的值返回其地址,類似于語(yǔ)言層&操作。當(dāng)值不可尋址時(shí)發(fā)生宕機(jī)
CanAddr() bool 表示值是否可尋址
CanSet() bool 返回值能否被修改。要求值可尋址且是導(dǎo)出的字段

值修改相關(guān)方法

使用 reflect.Value 修改值的相關(guān)方法如下表所示。

反射值對(duì)象修改值的方法

Set(x Value) 將值設(shè)置為傳入的反射值對(duì)象的值
Setlnt(x int64) 使用 int64 設(shè)置值。當(dāng)值的類型不是 int、int8、int16、 int32、int64 時(shí)會(huì)發(fā)生宕機(jī)
SetUint(x uint64) 使用 uint64 設(shè)置值。當(dāng)值的類型不是 uint、uint8、uint16、uint32、uint64 時(shí)會(huì)發(fā)生宕機(jī)
SetFloat(x float64) 使用 float64 設(shè)置值。當(dāng)值的類型不是 float32、float64 時(shí)會(huì)發(fā)生宕機(jī)
SetBool(x bool) 使用 bool 設(shè)置值。當(dāng)值的類型不是 bod 時(shí)會(huì)發(fā)生宕機(jī)
SetBytes(x []byte) 設(shè)置字節(jié)數(shù)組 []bytes值。當(dāng)值的類型不是 []byte 時(shí)會(huì)發(fā)生宕機(jī)
SetString(x string) 設(shè)置字符串值。當(dāng)值的類型不是 string 時(shí)會(huì)發(fā)生宕機(jī)

以上方法,在 reflect.Value 的 CanSet 返回 false 仍然修改值時(shí)會(huì)發(fā)生宕機(jī)。

在已知值的類型時(shí),應(yīng)盡量使用值對(duì)應(yīng)類型的反射設(shè)置值。

值可修改條件之一:可被尋址

通過(guò)反射修改變量值的前提條件之一:這個(gè)值必須可以被尋址。簡(jiǎn)單地說(shuō)就是這個(gè)變量必須能被修改。示例代碼如下:

package main

import (
    "reflect"
)

func main() {

    // 聲明整型變量a并賦初值
    var a int = 1024

    // 獲取變量a的反射值對(duì)象
    valueOfA := reflect.ValueOf(a)

    // 嘗試將a修改為1(此處會(huì)發(fā)生崩潰)
    valueOfA.SetInt(1)
}

程序運(yùn)行崩潰,打印錯(cuò)誤:

panic: reflect: reflect.Value.SetInt using unaddressable value

報(bào)錯(cuò)意思是:SetInt 正在使用一個(gè)不能被尋址的值。從 reflect.ValueOf 傳入的是 a 的值,而不是 a 的地址,這個(gè) reflect.Value 當(dāng)然是不能被尋址的。將代碼修改一下,重新運(yùn)行:

package main

import (
    "fmt"
    "reflect"
)

func main() {

    // 聲明整型變量a并賦初值
    var a int = 1024

    // 獲取變量a的反射值對(duì)象(a的地址)
    valueOfA := reflect.ValueOf(&a)

    // 取出a地址的元素(a的值)
    valueOfA = valueOfA.Elem()

    // 修改a的值為1
    valueOfA.SetInt(1)

    // 打印a的值
    fmt.Println(valueOfA.Int())
}

代碼輸出如下:

1

下面是對(duì)代碼的分析:

  • 第 14 行中,將變量 a 取值后傳給 reflect.ValueOf()。此時(shí) reflect.ValueOf() 返回的 valueOfA 持有變量 a 的地址。
  • 第 17 行中,使用 reflect.Value 類型的 Elem() 方法獲取 a 地址的元素,也就是 a 的值。reflect.Value 的 Elem() 方法返回的值類型也是 reflect.Value。
  • 第 20 行,此時(shí) valueOfA 表示的是 a 的值且可以尋址。使用 SetInt() 方法設(shè)置值時(shí)不再發(fā)生崩潰。
  • 第 23 行,正確打印修改的值。

提示

當(dāng) reflect.Value 不可尋址時(shí),使用 Addr() 方法也是無(wú)法取到值的地址的,同時(shí)會(huì)發(fā)生宕機(jī)。雖然說(shuō) reflect.Value 的 Addr() 方法類似于語(yǔ)言層的
&操作;Elem() 方法類似于語(yǔ)言層的
*操作,但并不代表這些方法與語(yǔ)言層操作等效。

值可修改條件之一:被導(dǎo)出

結(jié)構(gòu)體成員中,如果字段沒(méi)有被導(dǎo)出,即便不使用反射也可以被訪問(wèn),但不能通過(guò)反射修改,代碼如下:

package main

import (
    "reflect"
)

func main() {

    type dog struct {
            legCount int
    }
    // 獲取dog實(shí)例的反射值對(duì)象
    valueOfDog := reflect.ValueOf(dog{})

    // 獲取legCount字段的值
    vLegCount := valueOfDog.FieldByName("legCount")

    // 嘗試設(shè)置legCount的值(這里會(huì)發(fā)生崩潰)
    vLegCount.SetInt(4)
}

程序發(fā)生崩潰,報(bào)錯(cuò):

panic: reflect: reflect.Value.SetInt using value obtained using unexported field

報(bào)錯(cuò)的意思是:SetInt() 使用的值來(lái)自于一個(gè)未導(dǎo)出的字段。

為了能修改這個(gè)值,需要將該字段導(dǎo)出。將 dog 中的 legCount 的成員首字母大寫(xiě),導(dǎo)出 LegCount 讓反射可以訪問(wèn),修改后的代碼如下:

type dog struct {
    LegCount int
}

然后根據(jù)字段名獲取字段的值時(shí),將字符串的字段首字母大寫(xiě),修改后的代碼如下:

vLegCount := valueOfDog.FieldByName("LegCount")

再次運(yùn)行程序,發(fā)現(xiàn)仍然報(bào)錯(cuò):

panic: reflect: reflect.Value.SetInt using unaddressable value

這個(gè)錯(cuò)誤表示第 13 行構(gòu)造的 valueOfDog 這個(gè)結(jié)構(gòu)體實(shí)例不能被尋址,因此其字段也不能被修改。修改代碼,取結(jié)構(gòu)體的指針,再通過(guò) reflect.Value 的 Elem() 方法取到值的反射值對(duì)象。修改后的完整代碼如下:

package main

import (
    "reflect"
    "fmt"
)

func main() {

    type dog struct {
            LegCount int
    }
    // 獲取dog實(shí)例地址的反射值對(duì)象
    valueOfDog := reflect.ValueOf(&dog{})

    // 取出dog實(shí)例地址的元素
    valueOfDog = valueOfDog.Elem()

    // 獲取legCount字段的值
    vLegCount := valueOfDog.FieldByName("LegCount")

    // 嘗試設(shè)置legCount的值(這里會(huì)發(fā)生崩潰)
    vLegCount.SetInt(4)

    fmt.Println(vLegCount.Int())
}

代碼輸出如下:

4

代碼說(shuō)明如下:

  • 第 11 行,將 LegCount 首字母大寫(xiě)導(dǎo)出該字段。
  • 第 14 行,獲取 dog 實(shí)例指針的反射值對(duì)象。
  • 第 17 行,取 dog 實(shí)例的指針元素,也就是 dog 的實(shí)例。
  • 第 20 行,取 dog 結(jié)構(gòu)體中 LegCount 字段的成員值。
  • 第 23 行,修改該成員值。
  • 第 25 行,打印該成員值。

值的修改從表面意義上叫可尋址,換一種說(shuō)法就是值必須“可被設(shè)置”。那么,想修改變量值,一般的步驟是:

  1. 取這個(gè)變量的地址或者這個(gè)變量所在的結(jié)構(gòu)體已經(jīng)是指針類型。
  2. 使用 reflect.ValueOf 進(jìn)行值包裝。
  3. 通過(guò) Value.Elem() 獲得指針值指向的元素值對(duì)象(Value),因?yàn)橹祵?duì)象(Value)內(nèi)部對(duì)象為指針時(shí),使用 set 設(shè)置時(shí)會(huì)報(bào)出宕機(jī)錯(cuò)誤。
  4. 使用 Value.Set 設(shè)置值。

分享標(biāo)題:創(chuàng)新互聯(lián)GO教程:Go語(yǔ)言通過(guò)反射修改變量的值
瀏覽路徑:http://m.5511xx.com/article/dpiiogi.html