欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang?reflect反射的使用實(shí)例

 更新時(shí)間:2023年05月11日 11:36:51   作者:常魚(yú)  
Golang反射的錯(cuò)誤大多數(shù)都來(lái)自于調(diào)用了一個(gè)不適合當(dāng)前類(lèi)型的方法,而且,這些錯(cuò)誤通常是在運(yùn)行時(shí)才會(huì)暴露出來(lái),而不是在編譯時(shí),如果我們傳遞的類(lèi)型在反射代碼中沒(méi)有被覆蓋到那么很容易就會(huì)panic,本文就介紹一下使用go反射時(shí)很大概率會(huì)出現(xiàn)的錯(cuò)誤,需要的可以參考一下

首先有一段以下結(jié)構(gòu)體的定義

type User struct {
	UserName string
	UserId   int `name:"uid"`
}

初始化一個(gè)結(jié)構(gòu)體的實(shí)例

u := User{"octoboy", 101}

獲取字段名

首先獲取變量的Type變量

t := reflect.TypeOf(u)

需要注意的是,如果傳入的u是個(gè)指針,比如&User{"octoboy", 101}

if t.Kind() == reflect.Ptr {
	t = t.Elem()
}

這里通過(guò)Kind()函數(shù)獲取變量的類(lèi)型,判斷如果類(lèi)型為指針 需要使用Elem()獲取指針指向的內(nèi)容。

然后遍歷結(jié)構(gòu)體的字段,獲取其字段名稱(chēng)

	for i := 0; i < t.NumField(); i++ {
		fmt.Println(t.Field(i).Name)
	}

輸出結(jié)果:

UserName

UserId

獲取字段類(lèi)型和值

v := reflect.ValueOf(u)
if v.Kind() == reflect.Ptr { //類(lèi)型為指針 需要取elem
	v = v.Elem()
}

獲取字段的值或者賦值,需要用到ValueOf方法

for i := 0; i < v.NumField(); i++ {
	//v.Field(i).Int() v.Field(i).String() 都可以把值返回出來(lái),相當(dāng)于斷言 類(lèi)型不匹配會(huì)直接panic
	//直接斷成interface 任意類(lèi)型
	fmt.Println(v.Field(i).Interface())
}

輸出結(jié)果:

zyg

101

繼續(xù)輸出成員變量的類(lèi)型

for i := 0; i < v.NumField(); i++ {
	fmt.Println(v.Field(i).Kind())
}

輸出結(jié)果:

string

int

設(shè)置字段值

靜態(tài)賦值

	//設(shè)置字段值
	va := reflect.ValueOf(&u) //這里必須使用指針 否則后面調(diào)用Set無(wú)法使用無(wú)地址的值
	if va.Kind() == reflect.Ptr { //類(lèi)型為指針 需要取elem 意為取它指向的內(nèi)容值
		va = va.Elem()
	for i := 0; i < va.NumField(); i++ {
		//兩種方法取設(shè)置字段的值,第二種更為統(tǒng)一
		if va.Field(i).Kind() == reflect.String {
			//重要 如果需要使用set取修改u中的值,需要在ValueOf中傳入u的地址。否則會(huì)因?yàn)镾etString使用了一個(gè)不能被尋址的值而造成panic
			va.Field(i).SetString("octoboy")
		}
		if va.Field(i).Kind() == reflect.Int {
			va.Field(i).Set(reflect.ValueOf(123))
		}
	}

interface切片映射成結(jié)構(gòu)體(動(dòng)態(tài)賦值)

	//練手
	values := []interface{}{"octoboy", 123}
	for i := 0; i < va.NumField(); i++ {
		if reflect.ValueOf(values[i]).Kind() == va.Field(i).Kind() {
			va.Field(i).Set(reflect.ValueOf(values[i]))
		}
	}

打印以上兩種結(jié)構(gòu)題變量

輸出結(jié)果:

&{octoboy 123}

進(jìn)階—map映射成結(jié)構(gòu)體

有如下代碼

	//練習(xí) 把map映射成struct
	set := map[string]interface{}{
		"UserName": "zyg",
		"UserId":   101,
		"Age":      19,
		"Sex":      1,
	}
	user := &User{}
	MapToStruct(set, user)
	fmt.Println(user)

要求將map映射到user結(jié)構(gòu)題中,即如果User的字段名如存在于map的key中,則將對(duì)應(yīng)的value值賦給user結(jié)構(gòu)題的成員變量

有如下實(shí)現(xiàn)

//str類(lèi)型為interface{} 代表可以傳入任意的結(jié)構(gòu)體
func MapToStruct(m map[string]interface{}, str interface{}) {
	val := reflect.ValueOf(str)
	if val.Kind() != reflect.Ptr {//必須是指針 否則無(wú)法用Set賦值
		panic(any("must be ptr!"))
	}
	val = val.Elem()
	if val.Kind() != reflect.Struct { //指針指向的必須是結(jié)構(gòu)體
		panic(any("must be struct"))
	}
	for i := 0; i < val.NumField(); i++ {
		name := val.Type().Field(i).Name //value轉(zhuǎn)type后取字段名稱(chēng)
		if v, ok := m[name]; ok {        //如果根據(jù)tag做映射,就使用val.Type().Field(i).Tag.Get("name")作為key
			if reflect.ValueOf(v).Kind() == val.Field(i).Kind() {
				val.Field(i).Set(reflect.ValueOf(v))
			}
		}
	}
}

總結(jié)

1.TypeOf 用Name 獲取字段名,也可以用Kind獲取字段的類(lèi)型;ValueOf 只能用Kind獲取字段的類(lèi)型。

2.使用reflect.ValueOf(u).Type()轉(zhuǎn)成type,可以與reflect.TypeOf(u)達(dá)到一樣的效果

3.如果要使用Set,SetString等方法為其賦值,reflect.ValueOf(u)這里的u必須傳入一個(gè)指針,否則無(wú)法尋址,會(huì)出現(xiàn)panic

4.reflect.ValueOf(u).Interface()可以獲取值,在實(shí)際使用過(guò)程中往往會(huì)將返回結(jié)果斷言成一個(gè)接口類(lèi)型去調(diào)用接口函數(shù)

到此這篇關(guān)于golang reflect反射的使用實(shí)例的文章就介紹到這了,更多相關(guān)go reflect反射內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論