登录
首页 >  Golang >  Go问答

go开发中过度使用mapinterface{}?

来源:stackoverflow

时间:2024-04-30 14:21:39 208浏览 收藏

在Golang实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《go开发中过度使用mapinterface{}?》,聊聊,希望可以帮助到正在努力赚钱的你。

问题内容

我的大部分开发经验来自 php 和 javascript 等动态类型语言。通过在 golang 中重新创建一些旧的 php/javascript rest api,我已经练习 golang 大约一个月了。我觉得大多数时候我并没有以 golang 的方式做事。或者更一般地说,我不习惯使用强类型语言。我觉得我过度使用了 map[string]interface{} 及其片段来包装来自 http 请求的数据或作为 json http 输出发出的数据。那么我想知道的是,我要描述的内容是否违背了golang的开发理念?或者如果我违反了强类型语言的开发原则?

目前,我用 golang 重写的 rest api 程序流程大约 90% 都可以通过这 5 个步骤来描述。

第 1 步 - 接收数据

我从 http.request.parseform() 接收 http 表单数据,格式为 formvals := map[string][]string。有时我会存储需要解组的序列化 json 对象,例如 jsonuserinfo := json.unmarshal(formvals["user_information"][0]) /* 给出一些复杂的 json 对象 */

第 2 步 - 验证数据

我对 formvals 进行验证,以确保在 sql 查询中使用它之前所有数据值都是我所期望的。我将所有内容视为字符串,然后使用 regex 来确定字符串格式和业务逻辑是否有效(例如 isemail、isnumeric、isfloat、iscaslcompliant、iseligibleforvoting、islibrarycardexpired 等)。我已经为这些类型的验证编写了自己的正则表达式和自定义函数

第 3 步 - 将数据绑定到 sql 查询

我使用golang的database/sql.db来获取我的formvals并将它们绑定到我的查询和执行函数,例如query("select * from tbluser where user_id = ?, user_birthday > ? ",formvals["user_id"][ 0], jsonuserinfo["生日"]).我从不关心我作为要绑定的参数提供的数据类型,因此它们可能都是字符串。我相信上面步骤中的验证已确定它们可以用于 sql。

第 4 步 - 将 sql 结果绑定到 []map[string]interface{}{}

scan() 将查询结果写入 sqlresult := []map[string]interface{}{} 因为我不关心值类型是否为 null、字符串、浮点数、整数或其他类型。因此 sqlresult 的架构可能如下所示:

sqlresult =>
    [0] {
        "user_id":"1"
        "user_name":"bob smith"
        "age":"45"
        "weight":"34.22"
    },
    [1] {
        "user_id":"2"
        "user_name":"jane do"
        "age":nil
        "weight":"22.22"
    }

我编写了自己的急切加载函数,以便可以绑定更多信息,例如 eagerload("tbladdress", "join on tbladdress.user_id",&sqlresult),然后使用 []map 类型的更多信息填充 sqlresult [string]interface{}{},如下所示:

sqlResult =>
    [0] {
        "user_id":"1"
        "user_name":"Bob Smith"
        "age":"45"
        "weight":"34.22"
        "addresses"=>
            [0] {
                "type":"home"
                "address1":"56 Front Street West"
                "postal":"L3L3L3"
                "lat":"34.3422242"
                "lng":"34.5523422"
            }
            [1] {
                "type":"work"
                "address1":"5 Kennedy Avenue"
                "postal":"L3L3L3"
                "lat":"34.3422242"
                "lng":"34.5523422"
            }
    },
    [1] {
        "user_id":"2"
        "user_name":"Jane Do"
        "age":nil
        "weight":"22.22"
        "addresses"=>
            [0] {
                "type":"home"
                "address1":"56 Front Street West"
                "postal":"L3L3L3"
                "lat":"34.3422242"
                "lng":"34.5523422"
            }
    }

第 5 步 - json 编组并发送 http 响应

然后我执行 http.responsewriter.write(json.marshal(sqlresult)) 并为我的 rest api 输出数据

最近,我一直在重新审视带有代码示例的文章,这些代码示例在我本来会使用 map[string]interface{} 的地方使用结构。例如,我想使用其他 golang 开发人员会使用的更标准的方法来重构步骤 2。所以我找到了这个https://godoc.org/gopkg.in/go-演示/validator.v9,除了它的所有示例都是结构体。我还注意到,大多数谈论 database/sql 的博客都会将其 sql 结果扫描到类型化变量或具有类型化属性的结构中,而不是我的步骤 4,后者只是将所有内容放入 map[string]interface{}

因此,我开始写这个问题。我觉得 map[string] 接口{} 非常有用,因为大多数时候,我并不真正关心数据是什么,它让我可以在步骤 4 中自由地在我之前构建任何数据模式。将其转储为 json http 响应。我用尽可能少的代码来完成这一切。但这意味着我的代码还没有准备好利用 go 的验证工具,而且它似乎不符合 golang 社区的做事方式。

所以我的问题是,其他 golang 开发人员对步骤 2 和步骤 4 做了什么?特别是在第 4 步中……golang 开发人员真的鼓励通过结构和强类型属性指定数据模式吗?他们是否还指定具有强类型属性的结构以及他们进行的每个急切加载调用?这看起来是不是代码冗长了很多?


解决方案


这实际上取决于需求,就像您所说的那样,您不需要处理来自请求或 sql 结果的 json 。然后您可以轻松解组到 interface{}。并编组来自 sql 结果的 json。

对于第 2 步

golang 有一个库,用于验证结构体,用于使用内部字段的标签来解组 json。

https://github.com/go-playground/validator

type test struct {
    field `validate:"max=10,min=1"`
}

// max will be checked then min

你也可以去godoc获取validation library。这是使用struct标签验证json值的非常好的实现。

对于第 4 步

大多数时候,如果我们知道 json 的格式和数据,我们就会使用结构。因为它为我们提供了对数据类型和其他功能的更多控制。例如,如果您想要清空 json 字段,而您的 json 中不需要它。您应该将 struct 与 _ json 标记一起使用。

现在你已经说过你不关心来自sql的结果是否为空。但如果你再次这样做,就会涉及到使用 struct。您可以使用 sql.NullTypes 将结果扫描到结构中。如果您想在发送响应时 marshaling 数据时省略 json 对象,也可以为 omitempty 提供 json 标记。

结构体值编码为 json 对象。每个导出的结构体字段 成为对象的成员,使用字段名作为对象 键,除非由于下面给出的原因之一而省略该字段。

每个结构体字段的编码可以通过格式自定义 存储在结构字段标记中“json”键下的字符串。这 格式字符串给出字段的名称,后面可能跟着一个 以逗号分隔的选项列表。该名称可以为空,以便 指定选项而不覆盖默认字段名称。

“omitempty”选项指定应从 如果字段有空值,则编码,定义为 false、0、a nil 指针、nil 接口值以及任何空数组、切片、映射、 或字符串。

作为特殊情况,如果字段标记为“-”,则该字段始终为 省略。请注意,仍然可以使用以下命令生成名称为“-”的字段 标签“-,”。

json 标签示例

// Field appears in JSON as key "myName".
Field int `json:"myName"`

// Field appears in JSON as key "myName" and
// the field is omitted from the object if its value is empty,
// as defined above.
Field int `json:"myName,omitempty"`

// Field appears in JSON as key "Field" (the default), but
// the field is skipped if empty.
// Note the leading comma.
Field int `json:",omitempty"`

// Field is ignored by this package.
Field int `json:"-"`

// Field appears in JSON as key "-".
Field int `json:"-,"`

您可以从 golang 规范 json marshal 中给出的上述信息进行分析。struct 对 json 提供了如此多的控制。这就是 golang 开发人员最有可能使用结构的原因。

现在,在使用 map[string]interface{} 时,当您不知道来自服务器的 json 结构或字段类型时,应该使用它。大多数 golang 开发人员都会尽可能坚持使用结构。

文中关于的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《go开发中过度使用mapinterface{}?》文章吧,也可关注golang学习网公众号了解相关技术文章。

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>