3 回答
TA贡献1887条经验 获得超5个赞
您可以为“余额”字段使用带有自定义解组算法的自定义类型。
现在有两种可能:
处理两种类型:
package main
import (
"encoding/json"
"fmt"
"strconv"
)
type Int int
type account struct {
Name string
Balance Int
}
func (i *Int) UnmarshalJSON(b []byte) (err error) {
var s string
err = json.Unmarshal(b, &s)
if err == nil {
var n int
n, err = strconv.Atoi(s)
if err != nil {
return
}
*i = Int(n)
return
}
var n int
err = json.Unmarshal(b, &n)
if err == nil {
*i = Int(n)
}
return
}
func main() {
for _, in := range [...]string{
`{"Name": "foo", "Balance": 42}`,
`{"Name": "foo", "Balance": "111"}`,
} {
var a account
err := json.Unmarshal([]byte(in), &a)
if err != nil {
fmt.Printf("Error decoding JSON: %v\n", err)
} else {
fmt.Printf("Decoded OK: %v\n", a)
}
}
}
游乐场链接。
只处理一个数字类型,并通过一个合理的错误使其他任何事情失败:
package main
import (
"encoding/json"
"fmt"
)
type Int int
type account struct {
Name string
Balance Int
}
type FormatError struct {
Want string
Got string
Offset int64
}
func (fe *FormatError) Error() string {
return fmt.Sprintf("Invalid data format at %d: want: %s, got: %s",
fe.Offset, fe.Want, fe.Got)
}
func (i *Int) UnmarshalJSON(b []byte) (err error) {
var n int
err = json.Unmarshal(b, &n)
if err == nil {
*i = Int(n)
return
}
if ute, ok := err.(*json.UnmarshalTypeError); ok {
err = &FormatError{
Want: "number",
Got: ute.Value,
Offset: ute.Offset,
}
}
return
}
func main() {
for _, in := range [...]string{
`{"Name": "foo", "Balance": 42}`,
`{"Name": "foo", "Balance": "111"}`,
} {
var a account
err := json.Unmarshal([]byte(in), &a)
if err != nil {
fmt.Printf("Error decoding JSON: %#v\n", err)
fmt.Printf("Error decoding JSON: %v\n", err)
} else {
fmt.Printf("Decoded OK: %v\n", a)
}
}
}
游乐场链接。
还有第三种可能性:为整个account类型编写自定义解组器,但它需要更多涉及的代码,因为您需要使用encoding/json.Decoder类型的方法实际迭代输入 JSON 数据 。
看完你的
对于请求中任意数量的整数字段,在 Go 中处理传入请求并返回错误消息“余额必须是字符串”的最佳方法是什么?
更仔细,我承认有整个类型的定制解析器唯一明智的可能性,除非你是一个OK第三方软件包实现解析器通过JSON模式支持验证(我想我会看看这个第一次作为juju是一个相当已建立的产品)。
TA贡献1852条经验 获得超7个赞
对此的解决方案可能是使用类型断言,通过使用映射将 JSON 数据解组为:
type account struct {
Name string
Balance int
}
var str = `{
"name": "test@example.com",
"balance": "3"
}`
func main() {
var testing = map[string]interface{}{}
err := json.Unmarshal([]byte(str), &testing)
if err != nil {
fmt.Println(err)
}
val, ok := testing["balance"]
if !ok {
fmt.Println("missing field balance")
return
}
nv, ok := val.(float64)
if !ok {
fmt.Println("balance should be a number")
return
}
fmt.Printf("%+v\n", nv)
}
见http://play.golang.org/p/iV7Qa1RrQZ
使用这里的类型断言是float64因为它是 Go 的 JSON 解码器支持的默认数字类型。
应该注意的是,这种使用interface{}可能不值得麻烦。
该UnmarshalTypeError(https://golang.org/pkg/encoding/json/#UnmarshalFieldError)包含一个Offset领域,可能允许检索触发错误的JSON数据的内容。
例如,您可以返回以下类型的消息:
cannot unmarshal string into Go value of type int near `"balance": "3"`
TA贡献1873条经验 获得超9个赞
似乎这里提供了一个实现来解决这个问题,仅在 Go 中。
type account struct {
Name string
Balance int `json:",string"`
}
在我看来,更正确和可持续的方法是让你用 JavaScript 之类的东西创建一个客户端库,然后将它发布到 NPM 注册表中供其他人使用(私有存储库的工作方式相同)。通过提供这个库,你可以以一种有意义的方式为消费者定制 API,并防止错误蔓延到你的主程序中。
- 3 回答
- 0 关注
- 173 浏览
添加回答
举报