-1

我正在开发一个rest api,但由于某种原因无法将接口{} 键入到它的底层类型 - int。

我通过发布请求发送数据,以创建广告。它看起来像这样:

POST http://localhost:8080/api/ads
    {
        "Title": "Example Title",
        "Section": "machinery",
        "CostPerDayInCent": 34500,
        "Description": "A description",
        "User": 4,
        "AllowMobileContact": true,
        "AllowEmailContact": true,
        "IsActive": false
    }

传递的值被解码为 map[string]interface{},如下所示:

var adToValidate map[string]interface{}
err = json.NewDecoder(r.Body).Decode(&adToValidate)
    if err != nil {
        api.errorLog.Printf("Error decoding ad object: %v", err)
        http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
        return
    }

当我键入将 costperdayincent 和用户界面值断言为 int 时,我的问题发生了。

localScopeAd.CostPerDayInCent, ok = adMapToValidate[“CostPerDayInCent”].(int)
if !ok {
    fieldErrors[structFieldName] = fmt.Sprintf("%v value is not of int type", structFieldName)
}

if 语句执行,表明它不能键入 assert。为什么是这样?是不是因为传递的 json 将每个值都视为字符串?我将如何解决这个问题?

跟进

我在@DanielFarrell 的回答的帮助下解决了这个问题。

由于我无法在评论部分做出回应,以下是我解码为地图而不是结构的原因:

我知道解码成结构会更有意义。

我最初是在解码成一个结构。但是,我在尝试验证布尔值时遇到了一些问题。即“AllowMobileContact”:真,“AllowEmailContact”:真,“IsActive”:假

如果用户要发出发布请求以创建广告而忽略上述值。当请求正文被解码时,上述字段在结构中将默认为 false(布尔值 0)。如果我要验证传入的值,我将不知道用户是否输入了 false 或遗漏了整个键值对。

因为我想确保用户输入了这些值,所以我首先将其解码为一个映射,以便我可以检查 bool 键值对的键是否存在。然后,如果缺少一些必需的布尔数据,我可以发送相关响应。

如果您知道上述内容的更简单方法,我将有兴趣听到它。有一些 3rd 方包有 3 种布尔值类型,它们可能有效,但我决定改用上面的。

4

1 回答 1

0

我更愿意解码成一个结构并让json/encoding处理正确类型的工作。

type Input struct {
    Title,
    Selection string
    CostPerDayInCent int64
    Description      string
    User             int64
    AllowMobileContact,
    AllowEmailContact,
    IsActive bool
}

由于几个原因,这种方法非常普遍和有用。首先,您可以选择类型。其次,您正在定义一个类型,因此您可以附加函数,我发现它作为一种组织代码并避免将结构作为显式函数参数传递的方法非常方便。第三,您可以将注释附加到结构的字段,进一步调整解组。

最后,对我来说,最重要的是,您正在以 Go 处理数据的方式思考数据。在许多流行的现代语言(如 Python)中,代码和文档通常不会将类型附加到函数,或尝试显式枚举对象的属性。围棋不一样。它消除了固有的语言反射是它如此高效的原因之一。这可以为程序员提供巨大的好处——当您了解所有类型时,您就可以确切地知道事物的行为方式,并且可以准确地确定必须传递您调用的函数的内容。我建议您接受显式类型,并尽可能避免将 json 解码为面向接口的类型。你会知道你在处理什么,你也可以为你的消费者明确地定义它。

https://play.golang.org/p/egaequIT8ET与您的方法形成鲜明对比,您无需费心定义类型 - 但您也没有机会选择它们。

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
)

type Input struct {
    Title,
    Selection string
    CostPerDayInCent int64
    Description      string
    User             int64
    AllowMobileContact,
    AllowEmailContact,
    IsActive bool
}

func main() {
    var input = `{
        "Title": "Example Title",
        "Section": "machinery",
        "CostPerDayInCent": 34500,
        "Description": "A description",
        "User": 4,
        "AllowMobileContact": true,
        "AllowEmailContact": true,
        "IsActive": false
    }`
    // map[string]interface
    data := make(map[string]interface{})
    if err := json.NewDecoder(bytes.NewBufferString(input)).Decode(&data); err != nil {
        panic(err)
    }

    fmt.Printf("%f %T\n", data["CostPerDayInCent"], data["CostPerDayInCent"])

    // structure
    obj := new(Input)
    if err := json.NewDecoder(bytes.NewBufferString(input)).Decode(obj); err != nil {
        panic(err)
    }
    fmt.Printf("%d %T", obj.CostPerDayInCent, obj.CostPerDayInCent)
}
于 2021-10-29T23:25:42.530 回答