Golang Interface{} 不会将断言键入 int

Golang Interface{} wont type assert to int

我正在休息 api 但由于某种原因无法键入 assert an interface{} 到其基础类型 - int。

我通过 post 请求发送数据,以制作广告。看起来是这样的:

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

传递的值被解码为映射[string]接口{},如下所示:

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 的回答的帮助下解决了这个问题。

由于我无法在评论部分进行回复,以下是我解码为映射而不是结构的原因:

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

我最初是在解码成一个结构。但是,在尝试验证 bool 值时,我遇到了一些问题 运行 。 IE “AllowMobileContact”:真, “允许电子邮件联系”:是的, “IsActive”:假

如果用户提出 post 请求来制作广告而忽略了上述值。当请求主体被解码时,上述字段在结构中将默认为 false(bools 0 值)。 如果我当时要验证传入的值,我将不知道用户输入的是 false 还是遗漏了整个键值对。

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

如果您知道解决上述问题的更简单方法,我很想听听。有一些第 3 方包具有 3 个布尔值类型,它们可能有效,但我决定改用上面的。

我宁愿解码成一个结构体,让 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)
}