golang--reflect反射與字段相關的操作

一、通過reflect獲取結構體字段名、字段類型和字段值

//獲取結構體的類型:需要導入reflect包
package main

import (
	"fmt"
	"reflect"
)

//定義一個結構體
type UserData struct {
	Id   int
	Name string
}

func main() {
	//創建結構體的對象
	data := UserData{Id: 1, Name: "Jack"}
	//獲得結構體的類型
	data_t := reflect.TypeOf(data)
	fmt.Println("數據結構體的類型爲:", data_t.Name())
	//獲得結構體所有字段值
	data_v := reflect.ValueOf(data)
	//遍歷結構體類型的所有字段
	for i := 0; i < data_t.NumField(); i++ {
		data_f := data_t.Field(i)
		val := data_v.Field(i).Interface()
		fmt.Printf("字段名:%s, 字段類型:%v,  字段值:%v\n", data_f.Name, data_f.Type, val)
	}
}

運行結果如下:

數據結構體的類型爲: UserData
字段名:Id, 字段類型:int,  字段值:1
字段名:Name, 字段類型:string,  字段值:Jack

備註:

1、通過Interface()方法獲得字段的值時,字段的名首字母必須爲大寫,即必須是公有字段,否則無法通過反射獲取該字段,導致報錯:cannot return value obtained from unexported field or method;

2、獲取字段除了可以用Type.Field(index int)方法外,還可以用Type.FieldByIndex(index []int)、Type.FieldByName(name string)方法獲取。

 

2、通過reflect反射修改字段的值

package main

import (
	"fmt"
	"reflect"
)

type UserData struct {
	Id   int
	Name string
}

func main() {
	u := UserData{Id: 1, Name: "Jack"}

	fmt.Println("修改前的UserName:", u.Name)
	//通過反射獲取所有的字段數據
	data_f := reflect.ValueOf(&u).Elem()
	if k := data_f.Kind(); k == reflect.Struct {
		//通過字段名獲得字段數據
		field := data_f.FieldByName("Name")
		//判斷是否可以給字段賦值
		if fk := field.Kind(); fk == reflect.String && field.CanSet() {
			field.SetString("Jone")
			fmt.Println("修改後的UserName:", u.Name)
		}
	}
}

運行結果如下:

修改前的UserName: Jack
修改後的UserName: Jone

注意點:

1、獲取所有的字段數據時,需要傳入數據的指針(reflect.ValueOf(&data)),否則傳的的只是值的拷貝,並不能成功修改到原數據結構的字段值;

2、修改字段值前最好先用CanSet()方法判斷該字段是否可以賦值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章