好吧,标题有点误导。我所追求的如下:
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
}
Run Code Online (Sandbox Code Playgroud)
不要问:为什么我不使用CreateFromMap(int, string, int). 那个物体来自其他地方,不在我的控制范围内。
将映射中的每个键值对映射到结构体属性已经很无聊了。但是ok在每次转换后检查是否一切正常是混乱的。
除了反射,有没有更简单的方法来做到这一点?
假设我假设您不想使用反射,因为您不想自己做。在这种情况下,如何使用为您执行此操作的外部包?
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
}
Run Code Online (Sandbox Code Playgroud)
输出:
map[Age:42 Name:foo Id:17]
{Id:17 Name:foo Age:42}
Run Code Online (Sandbox Code Playgroud)
无论您的结构是什么样子,它都有优势,但它在内部使用反射。实际上,如果不对结构的每个属性使用反射和/或重复代码,我看不到任何“好”的方法来做您想做的事情。但是,缺点是您必须使用大写的属性,以便将它们导出到外部包。
在我看来,如果要在“创建”结构时指定附加规则,应该在解码操作之后。例如:
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
}
Run Code Online (Sandbox Code Playgroud)
这样,您将清楚地将“转换”部分与结构的特定规则处理分开。
| 归档时间: |
|
| 查看次数: |
8442 次 |
| 最近记录: |