将映射转换为结构

mos*_*ash 5 go

好吧,标题有点误导。我所追求的如下:

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在每次转换后检查是否一切正常是混乱的。

除了反射,有没有更简单的方法来做到这一点?

jul*_*enc 6

假设我假设您不想使用反射,因为您不想自己做。在这种情况下,如何使用为您执行此操作的外部包

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)

这样,您将清楚地将“转换”部分与结构的特定规则处理分开。