【问题标题】:How do I unmarshal a string value from a JSON document into a variable of type int?如何将 JSON 文档中的字符串值解组为 int 类型的变量?
【发布时间】:2017-11-09 16:09:55
【问题描述】:

我的结构:

type User struct {
    FirstName     string `json:"firstname, omitempty" validate:"required"` 
    LastName      string `json:"lastname, omitempty" validate:"required"`
    NumberofDays  int   `json:"numberofdays, string" validate:"min=0,max=100"`
}

NumberofDays 的值作为字符串从服务器传递,但我想检查它是否在范围内并存储为 int。

例如:user := &User{"Michael","Msk","3"}

我得到“无法将字符串解组为 int 类型的 Go 值”。

我不确定如何将类型转换为 int 并进行验证

【问题讨论】:

  • 您已将 NumberofDays 定义为 struct 标签中的一种字符串类型,您只能将 validate 标志与 int 类型一起使用。所以将字符串更改为 int 并传入 3 而不是 "3"
  • @retcentroot 所有值都作为字符串从服务器传递。我无法改变这一点。
  • 见我提供的例子。我还提供了一个使用“3”的替代方案。你可能无法控制这些值,但你绝对可以改变你的结构
  • 根据他们试图unmarshal而不是marshal的问题,但也许OP可以澄清。

标签: json go unmarshalling


【解决方案1】:

删除结构标签中逗号后的空格,例如json:"numberofdays, string" 应该是 json:"numberofdays,string"。有了空格,json 包会忽略 string 部分,因此您会收到错误消息。没有空格,错误就会消失,并且行为符合预期。

在此处比较两者的演示:https://play.golang.org/p/AUImnw_PIS

json 包结构标签的文档:https://golang.org/pkg/encoding/json/#Marshal

【讨论】:

  • 定义“它不工作”?您在问题中引用的错误是通过更改问题中引用的代码来修复的,如答案中所示。应用该修复后您遇到了什么问题?
  • 错误消息是:'无法将字符串解组为 int 类型的 Go 值'
  • 然后仔细检查你的结构标签。使用此答案中指示的正确结构标记,您应该不会收到该错误。
【解决方案2】:

您可以使用自定义类型来解组字符串 使用任何一组解析规则到一个整数值 您希望使用此映射:

package main

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

type User struct {
    FirstName    string `json:"firstname,omitempty" validate:"required"`
    LastName     string `json:"lastname,omitempty" validate:"required"`
    NumberofDays StrInt `json:"numberofdays" validate:"min=0,max=100"`
}

type StrInt int

func (si *StrInt) UnmarshalJSON(b []byte) error {
    var s string
    err := json.Unmarshal(b, &s)
    if err != nil {
        return err
    }

    n, err := strconv.ParseInt(s, 10, 0)
    if err != nil {
        return err
    }

    *si = StrInt(n)
    return nil
}

const data = `{
    "FirstName": "John",
    "LastName": "Doe",
    "NumberOfDays": "42"
}`

func main() {
    var u User
    err := json.Unmarshal([]byte(data), &u)
    if err != nil {
        panic(err)
    }
    fmt.Println(u)
}

Playground.

思路如下:

  1. 有一个自定义类型,主要是int,但允许在其上定义自定义方法。
  2. 通过在指向该类型的指针上实现UnmarshalJSON() 方法,使该类型满足encoding/json.Unmarshaler 接口。
  3. 在该方法中,首先将值解组为其本机类型—string—然后 然后将其解析为整数。

这种方法可能看起来很奇怪,但如果你能想到的话 还有一点,整数没有单一的“真实”字符串表示: 代表有不同的基础和不同的约定 即使是特定基数的整数。

在您的解组方法中,您实施文本表示的策略 你的整数。

【讨论】:

  • 您的示例代码中的结构标签无效。 struct 标记中逗号后的空格会导致 json 包忽略逗号后的所有内容。 在这种情况下不需要自定义类型和解组器
  • @Adrian,您能否引用有关通过字段标签映射类型的相关文档?
  • 已经从我的回答中链接了。它记录在json.Marshal 上,并在我的答案链接的操场示例中进行了演示。
  • @Adrian,现在找到了,谢谢。由于我的回答在技术上仍然是正确的,我已经更新了它的措辞,以免产生误导。顺便说一句,有趣的是,文档没有说明解释这些字符串的确切规则是什么。如果没有严格的行为规范,IMO 有点没用。
  • @Adrian,是的,看起来,“0xff”对于由,string 标签选项—an example 实现的解组规则不是一个有效的整数字符串表示。
【解决方案3】:

json 包为这些情况定义了一个自定义类型json.Number

【讨论】:

    猜你喜欢
    • 2022-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-23
    • 1970-01-01
    • 1970-01-01
    • 2017-11-20
    • 1970-01-01
    相关资源
    最近更新 更多