濮阳杆衣贸易有限公司

主頁(yè) > 知識(shí)庫(kù) > golang 如何用反射reflect操作結(jié)構(gòu)體

golang 如何用反射reflect操作結(jié)構(gòu)體

熱門標(biāo)簽:阿克蘇地圖標(biāo)注 外呼系統(tǒng)顯本地手機(jī)號(hào) 壽光微信地圖標(biāo)注 涿州代理外呼系統(tǒng) 電話機(jī)器人軟件免費(fèi) 百度地圖標(biāo)注后傳給手機(jī) excel地圖標(biāo)注分布數(shù)據(jù) 外呼系統(tǒng)用什么卡 評(píng)價(jià)高的400電話辦理

背景

需要遍歷結(jié)構(gòu)體的所有field

對(duì)于exported的field, 動(dòng)態(tài)set這個(gè)field的value

對(duì)于unexported的field, 通過強(qiáng)行取址的方法來獲取該值(tricky?)

思路

下面的代碼實(shí)現(xiàn)了從一個(gè)strct ptr對(duì)一個(gè)包外結(jié)構(gòu)體進(jìn)行取值的操作,這種場(chǎng)合在筆者需要用到反射的場(chǎng)合中出現(xiàn)比較多

simpleStrtuctField 函數(shù)接受一個(gè)結(jié)構(gòu)體指針,因?yàn)樽詈笙M淖兤渲?,所以傳參必須是指針。然后解引用?/p>

接下來遍歷結(jié)構(gòu)體的每個(gè)field, exported字段是CanInterface的,對(duì)于unexported字段,需要強(qiáng)行取址來獲取其值

model.go

package model
type Person struct {
 Name string
 age  int
}
func NewPerson(name string, age int) *Person {
 return Person{
  Name: name,
  age:  age,
 }
}

main.go

package main
import (
	"github.com/miaomiao3/log"
	"../model"
	"reflect"
	"unsafe"
)
func main() {
	person := model.NewPerson("haha", 12)
	log.Debug("before:%+v", person)
	simpleStrtuctField(person)
	simpleStrtuctField(person)
	log.Debug("after:%+v", person)
}
// get unexported field
func simpleStrtuctField(v interface{}) {
	dataType := reflect.TypeOf(v)
	dataValue := reflect.ValueOf(v)
	if dataType.Kind() == reflect.Ptr {
		if dataValue.IsNil() {
			panic("nil ptr")
		}
		// 如果是指針,則要判斷一下是否為struct
		originType := reflect.ValueOf(v).Elem().Type()
		if originType.Kind() != reflect.Struct {
			return
		}
		// 解引用
		dataValue = dataValue.Elem()
		dataType = dataType.Elem()
	} else {
		panic("non ptr")
	}
	num := dataType.NumField()
	for i := 0; i  num; i++ {
		field := dataType.Field(i)
		fieldName := field.Name
		fieldValue := dataValue.FieldByName(fieldName)
		if !fieldValue.IsValid() {
			continue
		}
		if fieldValue.CanInterface() {
			log.Debug("exported fieldName:%v value:%v", fieldName, fieldValue.Interface())
			if fieldValue.CanSet()  fieldValue.Kind() == reflect.String {
				oldValue := fieldValue.Interface().(string)
				fieldValue.SetString(oldValue + " auto append")
			}
		} else {
			// 強(qiáng)行取址
			forceValue := reflect.NewAt(fieldValue.Type(), unsafe.Pointer(fieldValue.UnsafeAddr())).Elem()
			log.Debug("unexported fieldName:%v value:%v", fieldName, forceValue.Interface())
		}
	}
}

output:

2019/06/02 17:15:31.64 [D] before:{Name:haha age:12}

2019/06/02 17:15:31.64 [D] exported fieldName:Name value:haha

2019/06/02 17:15:31.64 [D] unexported fieldName:age value:12

2019/06/02 17:15:31.64 [D] after:{Name:haha auto append age:12}

可以看到,Name字段被反射改變了,age的值也已經(jīng)獲取到

補(bǔ)充:go語(yǔ)言通過反射創(chuàng)建結(jié)構(gòu)體、賦值、并調(diào)用對(duì)應(yīng)方法

看代碼吧~

package main
import (
	"fmt"
	"reflect"
	"testing"
)
type Call struct {
	Num1 int
	Num2 int
}
func (call Call) GetSub(name string){
	fmt.Printf("%v 完成了減法運(yùn)算,%v - %v = %v \n", name, call.Num1, call.Num2, call.Num1 - call.Num2)
}
func (call *Call) GetSum(name string){
	fmt.Printf("%v 完成了加法運(yùn)算,%v + %v = %v \n", name, call.Num1, call.Num2, call.Num1 + call.Num2)
}
func TestReflect(t *testing.T) {
	var (
		call *Call
		rValues []reflect.Value
		rValues2 []reflect.Value
	)
	ptrType := reflect.TypeOf(call) //獲取call的指針的reflect.Type
	trueType := ptrType.Elem() //獲取type的真實(shí)類型
	ptrValue := reflect.New(trueType) //返回對(duì)象的指針對(duì)應(yīng)的reflect.Value
	call = ptrValue.Interface().(*Call)
	trueValue := ptrValue.Elem() //獲取真實(shí)的結(jié)構(gòu)體類型
	trueValue.FieldByName("Num1").SetInt(123)//設(shè)置對(duì)象屬性,注意這個(gè)一定要是真實(shí)的結(jié)構(gòu)類型的reflect.Value才能調(diào)用,指針類型reflect.Value的會(huì)報(bào)錯(cuò)
	//ptrValue.FieldByName("Num2").SetInt(23)
	trueValue.FieldByName("Num2").SetInt(23)
	//rValues = make([]reflect.Value, 0)
	rValues = append(rValues, reflect.ValueOf("xiaopeng"))//調(diào)用對(duì)應(yīng)的方法
	fmt.Println(rValues)
	trueValue.MethodByName("GetSub").Call(rValues)
	/*
	fixme 在反射中,指針的方法不可以給實(shí)際類型調(diào)用,實(shí)際類型的方法可以給指針類型調(diào)用,因?yàn)間o語(yǔ)言對(duì)這種操作做了封裝
	所以下面一句是沒問題的
	下下一句會(huì)運(yùn)行時(shí)報(bào)錯(cuò)
	 */
	//ptrValue.MethodByName("GetSub").Call(rValues)
	//trueValue.MethodByName("GetSum").Call(append(rValues2, reflect.ValueOf("hiram")))
	ptrValue.MethodByName("GetSum").Call(append(rValues2, reflect.ValueOf("hiram")))
	fmt.Println(call)
	
	/*
	fixme 在實(shí)際使用中  指針和實(shí)體都能相互轉(zhuǎn)換,不會(huì)影響調(diào)用
	但是指針的方法在方法體內(nèi)的操作會(huì)影響到結(jié)構(gòu)體本身屬性
	而實(shí)體的方法不會(huì),因?yàn)間o對(duì)于結(jié)構(gòu)體、數(shù)組、基本類型都是值傳遞
	 */
	call.GetSub("aaa")
	(*call).GetSub("bbb")
	call.GetSum("ccc")
	(*call).GetSum("ddd")
}

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。

您可能感興趣的文章:
  • golang 實(shí)現(xiàn)兩個(gè)結(jié)構(gòu)體復(fù)制字段
  • golang通過反射設(shè)置結(jié)構(gòu)體變量的值
  • Golang空結(jié)構(gòu)體struct{}用途,你知道嗎
  • golang修改結(jié)構(gòu)體中的切片值方法
  • Golang自定義結(jié)構(gòu)體轉(zhuǎn)map的操作
  • golang 結(jié)構(gòu)體初始化時(shí)賦值格式介紹
  • 解決golang結(jié)構(gòu)體tag編譯錯(cuò)誤的問題

標(biāo)簽:重慶 蘭州 吐魯番 欽州 銅川 汕頭 雞西 梅河口

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《golang 如何用反射reflect操作結(jié)構(gòu)體》,本文關(guān)鍵詞  golang,如,何用,反射,reflect,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《golang 如何用反射reflect操作結(jié)構(gòu)體》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于golang 如何用反射reflect操作結(jié)構(gòu)體的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    应用必备| 兴城市| 沁水县| 远安县| 中牟县| 崇信县| 荔浦县| 宝丰县| 青州市| 仪征市| 长岭县| 涪陵区| 额济纳旗| 汽车| 德江县| 青田县| 长寿区| 松溪县| 乌鲁木齐县| 肇源县| 东明县| 稻城县| 合水县| 敦化市| 抚远县| 怀远县| 宁城县| 白城市| 深泽县| 股票| 黄陵县| 襄汾县| 静乐县| 山阳县| 碌曲县| 乌兰察布市| 娄底市| 临江市| 神木县| 峡江县| 宝鸡市|