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

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

 更新時間:2021年04月28日 15:29:43   作者:皿小草  
這篇文章主要介紹了golang 用反射reflect操作結(jié)構(gòu)體的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

背景

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

對于exported的field, 動態(tài)set這個field的value

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

思路

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

simpleStrtuctField 函數(shù)接受一個結(jié)構(gòu)體指針,因為最后希望改變其值,所以傳參必須是指針。然后解引用。

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

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 {
			// 強行取址
			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)獲取到

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

看代碼吧~

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

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

相關(guān)文章

  • 如何使用?Go?和?Excelize?構(gòu)建電子表格

    如何使用?Go?和?Excelize?構(gòu)建電子表格

    這篇文章主要介紹了如何使用Go和Excelize構(gòu)建電子表格,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-09-09
  • GO中Json解析的幾種方式

    GO中Json解析的幾種方式

    本文主要介紹了GO中Json解析的幾種方式,詳細(xì)的介紹了幾種方法,?文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • Go語言基礎(chǔ)switch條件語句基本用法及示例詳解

    Go語言基礎(chǔ)switch條件語句基本用法及示例詳解

    這篇文章主要為大家介紹了Go語言基礎(chǔ)switch條件語句基本用法及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步
    2021-11-11
  • golang 監(jiān)聽服務(wù)的信號,實現(xiàn)平滑啟動,linux信號說明詳解

    golang 監(jiān)聽服務(wù)的信號,實現(xiàn)平滑啟動,linux信號說明詳解

    這篇文章主要介紹了golang 監(jiān)聽服務(wù)的信號,實現(xiàn)平滑啟動,linux信號說明詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Golang當(dāng)中的定時器實例詳解

    Golang當(dāng)中的定時器實例詳解

    這篇文章主要給大家介紹了關(guān)于Golang當(dāng)中定時器的相關(guān)資料,定時器的實現(xiàn)大家應(yīng)該都遇到過,最近在學(xué)習(xí)golang,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • Golang Gin框架中間件的用法詳解

    Golang Gin框架中間件的用法詳解

    中間件是Gin框架中的一個核心概念,它允許開發(fā)者在處理HTTP請求的過程中插入自定義的鉤子函數(shù),從而實現(xiàn)諸如日志記錄、身份驗證、權(quán)限控制等公共邏輯,本文將結(jié)合實際案例,詳細(xì)講解Gin框架中間件的用法
    2024-10-10
  • golang代碼檢測工具之goimports解讀

    golang代碼檢測工具之goimports解讀

    這篇文章主要介紹了golang代碼檢測工具之goimports使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • golang通過遞歸遍歷生成樹狀結(jié)構(gòu)的操作

    golang通過遞歸遍歷生成樹狀結(jié)構(gòu)的操作

    這篇文章主要介紹了golang通過遞歸遍歷生成樹狀結(jié)構(gòu)的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go語言學(xué)習(xí)之JSON編碼解析與使用

    Go語言學(xué)習(xí)之JSON編碼解析與使用

    這篇文章主要為大家詳細(xì)介紹了Go語言中JSON編碼的解析與使用已經(jīng)JSON與Map、結(jié)構(gòu)體的互相轉(zhuǎn)化,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2023-02-02
  • Golang使用切片實現(xiàn)單鏈表的示例代碼

    Golang使用切片實現(xiàn)單鏈表的示例代碼

    單鏈表(Single?Linked?List)是鏈表數(shù)據(jù)結(jié)構(gòu)的一種實現(xiàn)方式,它包含一系列節(jié)點(Node),每個節(jié)點都包含一個數(shù)據(jù)域和一個指向下一個節(jié)點的指針,本文給大家介紹了Golang使用切片實現(xiàn)單鏈表的操作,需要的朋友可以參考下
    2024-05-05

最新評論