@phper
2021-02-09T11:53:13.000000Z
字数 8911
阅读 1969
Golang
type Man struct {
Id int
Name string
}
s1 := make([]Man, 0)
s1 = append(s1, Man{1, "a"})
s1 = append(s1, Man{2, "b"})
s1 = append(s1, Man{3, "c"})
func(v interface{}) {
getValue := reflect.ValueOf(v) // Value of v
if getValue.Kind() != reflect.Slice {
panic("need slice kind")
}
l := getValue.Len()
for i := 0; i < l; i++ {
value := getValue.Index(i) // Value of item
typel := value.Type() // Type of item
if typel.Kind() != reflect.Struct {
panic("need struct kind")
}
fmt.Printf("type-kind: %s, type-name: %s, value: %v\n", typel.Kind(), typel.Name(), value.Interface())
num := value.NumField()
for j := 0; j < num; j++ {
fmt.Printf("name: %s, type: %s, value: %v\n", typel.Field(j).Name, value.Field(j).Type(), value.Field(j).Interface())
}
fmt.Println()
}
}(s1)
执行打印:
type-kind: struct, type-name: Man, value: {1 a}
name: Id, type: int, value: 1
name: Name, type: string, value: a
type-kind: struct, type-name: Man, value: {2 b}
name: Id, type: int, value: 2
name: Name, type: string, value: b
type-kind: struct, type-name: Man, value: {3 c}
name: Id, type: int, value: 3
name: Name, type: string, value: c
根据示例:
通过 reflect.ValueOf(v)
得到 v 的 Value 对象,它的 Len()
方法可以得到切片
的长
度;
通过 Value 对象的 Index(i)
方法得到第 i 的元素 Value 对象,然后通过 Value 对象得到 Type 对象;
值得注意的是:
Index
方法可以适用于获取 Array, Slice, or String 其中的字段
Len
方法获取长度,可以适用于 Array, Chan, Map, Slice, or String
Filed
方法用于Struct的其中字段。
NumField
方法,用于获取Struct的长度。
package main
import (
"fmt"
"reflect"
)
type User struct {
Id int `json:"id"`
Name string `json:"name"`
addr string `json:"_"`
}
func main(){
u := User{Id:1001, Name:"aaa" , addr:"bbb"}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
for i := 0; i < v.NumField(); i++ {
if v.Field(i).CanInterface() { //判断是否为可导出字段
fmt.Printf("%s %s = %v -tag:%s n",
t.Field(i).Name,
t.Field(i).Type,
v.Field(i).Interface(),
t.Field(i).Tag)
}
}
}
执行打印:
Id int = 1001 -tag:json:"id"
Name string = aaa -tag:json:"name"
注:当结构体中含有非导出字段时,v.Field(i).Interface()
会panic
, 所以使用v.Field(i).CanInterface()
先判断一下
package main
import (
"reflect"
"fmt"
)
type User struct {
Id int
Name string
Address Address
}
type Address struct {
Add string
Res int
}
func main(){
u := User{Id:1001, Name:"aaa" , Address:Address{Add:"ccccccccc", Res:12}}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
for i := 0; i < v.NumField(); i++ {
//判断是否为可导出字段
if v.Field(i).CanInterface() {
//判断是否是嵌套结构
if v.Field(i).Type().Kind() == reflect.Struct{
structField := v.Field(i).Type()
for j :=0 ; j< structField.NumField(); j++ {
fmt.Printf("%s %s = %v -tag:%s \n",
structField.Field(j).Name,
structField.Field(j).Type,
v.Field(i).Field(j).Interface(),
structField.Field(j).Tag)
}
} else {
fmt.Printf("%s %s = %v -tag:%s \n",
t.Field(i).Name,
t.Field(i).Type,
v.Field(i).Interface(),
t.Field(i).Tag)
}
}
}
}
打印:
Id int = 1001 -tag:
Name string = aaa -tag:
Add string = ccccccccc -tag:
Res int = 12 -tag:
package main
import (
"reflect"
"fmt"
)
func main(){
var data []int
data = []int{1, 2, 3, 4}
//反射值
v := reflect.ValueOf(data)
//数组/切片长度
dataNum := v.Len()
for i := 0; i < dataNum; i++ {
fmt.Printf("%v, ", v.Index(i).Interface())
}
}
打印:
1,2,3,4,
package main
import (
"fmt"
"reflect"
)
type Student struct {
Name string `json:"name"`
Age uint `json:"age"`
}
type Teacher struct {
Name string `json:"name"`
Gender uint `json:"gender"`
}
// StructSliceToMapSlice : struct切片转为map切片
func StructSliceToMapSlice(source interface{}) {
// 判断,interface转为[]interface{}
v := reflect.ValueOf(source)
if v.Kind() != reflect.Slice {
panic("ERROR: Unknown type, slice expected.")
}
l := v.Len()
ret := make([]interface{}, l)
for i := 0; i < l; i++ {
ret[i] = v.Index(i).Interface()
}
// 转换之后的结果变量
res := make([]map[string]interface{}, 0)
// 通过遍历,每次迭代将struct转为map
for _, elem := range ret {
data := make(map[string]interface{})
objT := reflect.TypeOf(elem)
objV := reflect.ValueOf(elem)
for i := 0; i < objT.NumField(); i++ {
data[objT.Field(i).Name] = objV.Field(i).Interface()
}
res = append(res, data)
}
fmt.Printf("==== Convert Result ====\n%+v\n", res)
}
func main() {
var people []interface{}
// 切片添加Student元素
stu1 := Student{
Name: "Ame",
Age: 18,
}
stu2 := Student{
Name: "Maybe",
Age: 20,
}
people = append(people, stu1)
people = append(people, stu2)
// 切片添加Teacher元素
tech := Teacher{
Name: "Rotk",
Gender: 0,
}
people = append(people, tech)
StructSliceToMapSlice(people)
}
打印:
==== Convert Result ====
[map[Age:18 Name:Ame] map[Age:20 Name:Maybe] map[Gender:0 Name:Rotk]]
func MapToStruct(mapData map[string]string, result interface{}) error {
if reflect.ValueOf(result).Kind() != reflect.Ptr {
return e.setErrorInfo(errors.New("第二参数请传指针变量!"))
}
if reflect.ValueOf(result).IsNil() {
return e.setErrorInfo(errors.New("第二参数不能是空指针!"))
}
//获取元素值
v := reflect.ValueOf(result).Elem()
t := v.Type()
//遍历结构体
for i := 0; i < t.NumField(); i++ {
//看下是否有sql别名
sqlTag := t.Field(i).Tag.Get("sql")
var fieldName string
if sqlTag != "" {
fieldName = strings.Split(sqlTag, ",")[0]
} else {
fieldName = t.Field(i).Name
}
//从map中取值
value, ok := mapData[fieldName]
if !ok {
continue
}
switch v.Field(i).Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
res, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return e.setErrorInfo(err)
}
v.Field(i).SetInt(res)
case reflect.String:
v.Field(i).SetString(value)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
res, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return e.setErrorInfo(err)
}
v.Field(i).SetUint(res)
case reflect.Float32:
res, err := strconv.ParseFloat(value, 32)
if err != nil {
return e.setErrorInfo(err)
}
v.Field(i).SetFloat(res)
case reflect.Float64:
res, err := strconv.ParseFloat(value, 64)
if err != nil {
return e.setErrorInfo(err)
}
v.Field(i).SetFloat(res)
case reflect.Bool:
res, err := strconv.ParseBool(value)
if err != nil {
return e.setErrorInfo(err)
}
v.Field(i).SetBool(res)
case reflect.Slice:
var strArray []string
var valArray []reflect.Value
var valArr reflect.Value
elemKind := v.Field(i).Type().Elem().Kind()
elemType := t.Field(i).Type.Elem()
value = strings.Trim(strings.Trim(value, "["), "]")
strArray = strings.Split(value, ",")
switch elemKind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
for _, e := range strArray {
ee, err := strconv.ParseInt(e, 10, 64)
if err != nil {
return err
}
valArray = append(valArray, reflect.ValueOf(ee).Convert(elemType))
}
case reflect.String:
for _, e := range strArray {
valArray = append(valArray, reflect.ValueOf(strings.Trim(e, "\"")).Convert(elemType))
}
}
valArr = reflect.Append(v.Field(i), valArray...)
v.Field(i).Set(valArr)
}
}
return nil
}
测试一下:
m1 := map[string]string{"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username":"EE2"}
type User2 struct {
Uid string `sql:"uid,auto_increment"`
Username string `sql:"username"`
Departname string `sql:"departname"`
Created string `sql:"created"`
Status int64 `sql:"status"`
}
user3 := new(User2)
err := MapToStruct(m1, user3)
fmt.Printf("%+v", user3)
//输出: &{Uid:131733 Username:EE2 Departname:233 Created:2021-12-12 Status:2}
func MapSliceToStructSlice(mapSliceData []map[string]string, values interface{}) error {
//原始struct的切片值
destSlice := reflect.ValueOf(values).Elem()
//原始单个struct的类型
destType := destSlice.Type().Elem()
//遍历切片
for j := 0; j < len(mapSliceData); j++ {
//新建1个原始struct的类型
dest := reflect.New(destType).Elem()
//遍历结构体
for i := 0; i < destType.NumField(); i++ {
//看下是否有sql别名
sqlTag := destType.Field(i).Tag.Get("sql")
var fieldName string
if sqlTag != "" {
fieldName = strings.Split(sqlTag, ",")[0]
} else {
fieldName = destType.Field(i).Name
}
//从map中取值
value, ok := mapSliceData[j][fieldName]
if !ok {
continue
}
//无法赋值
if !dest.Field(i).CanSet() {
continue
}
switch dest.Field(i).Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
res, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return e.setErrorInfo(err)
}
dest.Field(i).SetInt(res)
case reflect.String:
dest.Field(i).SetString(value)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
res, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return e.setErrorInfo(err)
}
dest.Field(i).SetUint(res)
case reflect.Float32:
res, err := strconv.ParseFloat(value, 32)
if err != nil {
return e.setErrorInfo(err)
}
dest.Field(i).SetFloat(res)
case reflect.Float64:
res, err := strconv.ParseFloat(value, 64)
if err != nil {
return e.setErrorInfo(err)
}
dest.Field(i).SetFloat(res)
case reflect.Bool:
res, err := strconv.ParseBool(value)
if err != nil {
return e.setErrorInfo(err)
}
dest.Field(i).SetBool(res)
}
}
//赋值
destSlice.Set(reflect.Append(destSlice, dest))
}
return nil
}
或者,我们简化一下套用上面的MapToStruct
:
func MapSliceToStructSlice(mapSliceData []map[string]string, values interface{}) error {
//原始struct的切片值
destSlice := reflect.ValueOf(values).Elem()
//原始单个struct的类型
destType := destSlice.Type().Elem()
//遍历切片
for j := 0; j < len(mapSliceData); j++ {
//新建1个原始struct的类型
dest := reflect.New(destType).Elem()
//循环调用
err := e.MapToStruct(mapSliceData[j], dest.Addr().Interface())
if err != nil {
return err
}
//赋值
destSlice.Set(reflect.Append(destSlice, dest))
}
return nil
}
测试一下:
m1 := []map[string]string{{"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username": "EE2"}, {"created": "2021-12-12", "departname": "233", "status": "2", "uid": "131733", "username": "EE2"}}
type User2 struct {
Uid int `sql:"uid,auto_increment"`
Username string `sql:"username"`
Departname string `sql:"departname"`
Created string `sql:"created"`
Status int64 `sql:"status"`
}
var user3 []User2
err = MapSliceToStructSlice(m1, &user3)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Printf("%#v", user3)
打印结果如下:
[]main.User2{main.User2{Uid:131733, Username:"EE2", Departname:"233", Created:"2021-12-12", Status:2}, main.User2{Uid:131733, Username:"EE2", Departname:"233", Created:"2021-12-12", Status:2}}