好的,标题有点误导。我所追求的如下:
type MyStruct struct {
id int
name string
age int
}
func CreateFromMap(m map[string]interface{}) (MyStruct, error) {
var (
id int
name string
age int
ok bool
)
err := errors.New("Error!")
id, ok = m["id"].(int)
if !ok {
return nil, err
}
name, ok = m["name"].(string)
if !ok {
return nil, err
}
age, ok = m["age"].(int)
if !ok {
return nil, err
}
return MyStruct{id, name, age}, nil
}
不要问:为什么我没有使用CreateFromMap(int, string, int)
。那个对象来自其他地方,不受我的控制。
将地图中的每个键值对映射到struct属性已经很无聊了。但是在每次转换后检查是否所有内容都是ok
是混乱的。
除了反思之外,还有更简单的方法吗?
答案 0 :(得分:2)
让我们假设你不想使用反思,因为你不想自己做。在这种情况下,使用external package为你做什么呢?
package main
import "fmt"
import "github.com/mitchellh/mapstructure"
type MyStruct struct {
Id int
Name string
Age int
}
func main() {
var m = make(map[string]interface{})
m["Id"] = 17
m["Name"] = "foo"
m["Age"] = 42
fmt.Printf("%+v\n", m)
res, err := CreateFromMap(m)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", res)
}
func CreateFromMap(m map[string]interface{}) (MyStruct, error) {
var result MyStruct
err := mapstructure.Decode(m, &result)
return result, err
}
输出:
map[Age:42 Name:foo Id:17]
{Id:17 Name:foo Age:42}
它的优点是可以处理您的结构,但它在内部使用反射。实际上,我没有看到任何好的"如何在不使用结构的每个属性的反射和/或重复代码的情况下执行您想要的操作。然而,缺点是您必须使用大写属性,以便将它们导出到外部包。
在我看来,如果你想在"创建"时指定其他规则。结构,应该是解码后的操作。 例如:
func CreateFromMap(m map[string]interface{}) (MyStruct, error) {
var result MyStruct
err := mapstructure.Decode(m, &result)
if err != nil {
return result, err
}
if result.Age <= 0 {
result.Age = 0
}
if result.Name == "" {
return result, errors.New("empty name is not allowed")
}
return result, err
}
通过这种方式,您可以明确区分&#34;转换&#34;部分来自您的结构的特定规则处理。
答案 1 :(得分:2)
你可以只是Marshal / Unmarshal,但属性名称应匹配
func CreateFromMap(m map[string]interface{}) (MyStruct, error) {
data, _ := json.Marshal(m)
var result MyStruct
err := json.Unmarshal(data, &result)
return result, err
}