我想在Golang中将结构转换为map。如果我可以将JSON标记用作创建的映射中的键(否则默认为字段名称),这也很好。
如果您想要将结构转换为地图的快速解决方案,请参阅accepted answer,对其进行投票并使用该包。
快乐的编码! :)
到目前为止我有这个功能,我正在使用反射包但我不太清楚如何使用该包,请耐心等待。
func ConvertToMap(model interface{}) bson.M {
ret := bson.M{}
modelReflect := reflect.ValueOf(model)
if modelReflect.Kind() == reflect.Ptr {
modelReflect = modelReflect.Elem()
}
modelRefType := modelReflect.Type()
fieldsCount := modelReflect.NumField()
var fieldData interface{}
for i := 0; i < fieldsCount; i++ {
field := modelReflect.Field(i)
switch field.Kind() {
case reflect.Struct:
fallthrough
case reflect.Ptr:
fieldData = ConvertToMap(field.Interface())
default:
fieldData = field.Interface()
}
ret[modelRefType.Field(i).Name] = fieldData
}
return ret
}
我还查看了JSON包的源代码,因为它应该包含我需要的实现(或部分内容),但不太了解。
答案 0 :(得分:103)
我也需要这样的东西。我正在使用一个将结构转换为地图的内部包。我决定用其他基于struct
的高级函数开源。看看:
https://github.com/fatih/structs
它支持:
[]string
[]values
您可以在此处看到一些示例:http://godoc.org/github.com/fatih/structs#pkg-examples 例如,将结构转换为地图很简单:
type Server struct {
Name string
ID int32
Enabled bool
}
s := &Server{
Name: "gopher",
ID: 123456,
Enabled: true,
}
// => {"Name":"gopher", "ID":123456, "Enabled":true}
m := structs.Map(s)
structs
包支持匿名(嵌入)字段和嵌套结构。该包提供通过字段标签过滤某些字段。
答案 1 :(得分:18)
从struct
到map[string]interface{}
package main
import (
"fmt"
"encoding/json"
)
type MyData struct {
One int
Two string
Three int
}
func main() {
in := &MyData{One: 1, Two: "second"}
var inInterface map[string]interface{}
inrec, _ := json.Marshal(in)
json.Unmarshal(inrec, &inInterface)
// iterate through inrecs
for field, val := range inInterface {
fmt.Println("KV Pair: ", field, val)
}
}
答案 2 :(得分:8)
这是我过去编写的一个函数,用于将结构转换为地图,使用标记作为键
// ToMap converts a struct to a map using the struct's tags.
//
// ToMap uses tags on struct fields to decide which fields to add to the
// returned map.
func ToMap(in interface{}, tag string) (map[string]interface{}, error){
out := make(map[string]interface{})
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// we only accept structs
if v.Kind() != reflect.Struct {
return nil, fmt.Errorf("ToMap only accepts structs; got %T", v)
}
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
// gets us a StructField
fi := typ.Field(i)
if tagv := fi.Tag.Get(tag); tagv != "" {
// set key of map to value in struct field
out[tagv] = v.Field(i).Interface()
}
}
return out, nil
}
Runnable example here.
注意,如果您有多个具有相同标记值的字段,那么您显然无法将它们全部存储在地图中。如果发生这种情况,可能会谨慎地返回错误。
答案 3 :(得分:4)
我喜欢接受的答案的可导入包,但是它不翻译我的json别名。我的大多数项目都有我导入的辅助函数/类。
这是一个可以解决我的特定问题的函数。
// Converts a struct to a map while maintaining the json alias as keys
func StructToMap(obj interface{}) (newMap map[string]interface{}, err error) {
data, err := json.Marshal(obj) // Convert to a json string
if err != nil {
return
}
err = json.Unmarshal(data, &newMap) // Convert to a map
return
}
总的来说,这就是它的称呼...
package main
import (
"fmt"
"encoding/json"
"github.com/fatih/structs"
)
type MyStructObject struct {
Email string `json:"email_address"`
}
func main() {
obj := &MyStructObject{Email: "test@test.com"}
// My solution
fmt.Println(StructToMap(obj)) // prints {"email_address": "test@test.com"}
// The currently accepted solution
fmt.Println(structs.Map(obj)) // prints {"Email": "test@test.com"}
}
答案 4 :(得分:0)
package main
import (
"fmt"
"reflect"
)
type bill struct {
N1 int
N2 string
n3 string
}
func main() {
a := bill{4, "dhfthf", "fdgdf"}
v := reflect.ValueOf(a)
values := make(map[string]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
if v.Field(i).CanInterface() {
values[v.Type().Field(i).Name] = v.Field(i).Interface()
} else {
fmt.Printf("sorry you have a unexported field (lower case) value you are trying to sneak past. I will not allow it: %v\n", v.Type().Field(i).Name)
}
}
fmt.Println(values)
passObject(&values)
}
func passObject(v1 *map[string]interface{}) {
fmt.Println("yoyo")
}
答案 5 :(得分:0)
map := Structpb.AsMap()
// map is the map[string]interface{}