如何将来自JSON的0和false都解组为bool

Wil*_*zuk 8 json go

目前我正在映射一个服务的输出,比如说,它可以自由地为它的布尔类型交换0和false(以及1和true).有没有办法为内置编码/ json unmarshal函数使用更宽松的解析器?我试过添加,字符串到json标签无济于事.

我想要的一个例子:

type MyType struct {
    AsBoolean bool `json:"field1"`
    AlsoBoolean bool `json:"field2"`
}
Run Code Online (Sandbox Code Playgroud)

那么,给定输入json:

{
    "field1" : true,
    "field2" : 1
}
Run Code Online (Sandbox Code Playgroud)

结果结构将是:

obj := MyType{}
json_err := json.Unmarshal([]byte(input_json), &obj)
fmt.Printf("%v\n", obj.AsBoolean) //"true"
fmt.Printf("%v\n", obj.AlsoBoolean) //"true"
Run Code Online (Sandbox Code Playgroud)

Wil*_*zuk 9

结束使用一个特殊的"布尔"类型,并在我使用普通bool的地方,交换为此:

type ConvertibleBoolean bool

func (bit ConvertibleBoolean) UnmarshalJSON(data []byte) error {
    asString := string(data)
    if asString == "1" || asString == "true" {
        bit = true
    } else if asString == "0" || asString == "false" {
        bit = false
    } else {
        return errors.New(fmt.Sprintf("Boolean unmarshal error: invalid input %s", asString))
    }
    return nil
}
Run Code Online (Sandbox Code Playgroud)

  • 还有一个小提示:有一个方法[`fmt.Errorf()`](https://golang.org/pkg/fmt/#Errorf)所以你不需要`errors.New()`和`fmt .Sprintf()`.(顺便说一下`fmt.Error()`在引擎盖下完全一样.) (3认同)
  • 你可能想看看 [`strconv.ParseBool`](https://golang.org/pkg/strconv/#ParseBool) (3认同)
  • 小提示:Go样式约定是使用`mixedCaps`(https://golang.org/doc/effective_go.html#mixed-caps)变量名,所以`as_string`应该是`asString`(或者只是`s`如果这是一个小功能). (2认同)

Dre*_*eur 8

谢谢Will Charzuck的答案,但是,除非我使用指针方法接收器,并且在函数体中设置指针的值,否则它对我不起作用.

type ConvertibleBoolean bool

func (bit *ConvertibleBoolean) UnmarshalJSON(data []byte) error {
    asString := string(data)
    if asString == "1" || asString == "true" {
        *bit = true
    } else if asString == "0" || asString == "false" {
        *bit = false
    } else {
        return errors.New(fmt.Sprintf("Boolean unmarshal error: invalid input %s", asString))
    }
    return nil
}
Run Code Online (Sandbox Code Playgroud)


Twi*_*ain 6

这是我的看法。如果您需要一些东西来处理一些额外的情况。根据需要添加更多。

// so you know what's needed.
import (
    "encoding/json"
    "strconv"
    "strings"
)

// NumBool provides a container and unmarshalling for fields that may be
// boolean or numbrs in the WebUI API.
type NumBool struct {
    Val bool
    Num float64
}

// UnmarshalJSON parses fields that may be numbers or booleans.
func (f *NumBool) UnmarshalJSON(b []byte) (err error) {
    switch str := strings.ToLower(strings.Trim(string(b), `"`)); str {
    case "true":
        f.Val = true
    case "false":
        f.Val = false
    default:
        f.Num, err = strconv.ParseFloat(str, 64)
        if f.Num > 0 {
            f.Val = true
        }
    }
    return err
}
Run Code Online (Sandbox Code Playgroud)

在操场上看到它。

我也知道这样的事情:

// FlexBool provides a container and unmarshalling for fields that may be
// boolean or strings in the Unifi API.
type FlexBool struct {
    Val bool
    Txt string
}

// UnmarshalJSON method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false.
// Really it converts ready, ok, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false.
func (f *FlexBool) UnmarshalJSON(b []byte) error {
    if f.Txt = strings.Trim(string(b), `"`); f.Txt == "" {
        f.Txt = "false"
    }
    f.Val = f.Txt == "1" || strings.EqualFold(f.Txt, "true") || strings.EqualFold(f.Txt, "yes") ||
        strings.EqualFold(f.Txt, "t") || strings.EqualFold(f.Txt, "armed") || strings.EqualFold(f.Txt, "active") ||
        strings.EqualFold(f.Txt, "enabled") || strings.EqualFold(f.Txt, "ready") || strings.EqualFold(f.Txt, "up") ||
        strings.EqualFold(f.Txt, "ok")
    return nil
}
Run Code Online (Sandbox Code Playgroud)

如果你想变得很小:

// Bool allows 0/1 and "0"/"1" and "true"/"false" (strings) to also become boolean.
type Bool bool

func (bit *Bool) UnmarshalJSON(b []byte) error {
    // txt := string(b) // original, no strings.
    txt := string(bytes.Trim(b, `"`))
    *bit = Bool(txt == "1" || txt == "true")
    return nil
}
Run Code Online (Sandbox Code Playgroud)

在操场上看到这个: bool/int/string。旧版本:playground: bool/int