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)
}
我正在休息 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)
}