简洁的 nil 检查结构字段指针?

Concise nil checks for struct field pointers?

假设我有这个结构:

type Foo struct {
    Bar        *string          `json:"bar"`
    Baz        *int64           `json:"baz,omitempty"`
    Qux        *string          `json:"qux"`
    Quux       string           `json:"quux"`
}

解组 json 后,我像这样检查 nil:

switch {
case f.Bar == nil:
    return errors.New("Missing 'bar'")
case f.Baz == nil:
    f.Baz = 42
case f.Qux == nil:
    return errors.New("Missing 'qux'")
}

(或通过一系列 if 语句等...)

我知道我可以将所有 nil 比较放在一个逗号分隔 case 中,但是每个 nil 检查都会有不同的 returns.

我的问题:是否有更简单的 nil 检查方法?

问你一个问题:你想减少多少冗长?因为你想在不同的条件下做不同的事情(不同的领域是nil)。您的代码包含这些不同的东西和不同的条件。除此之外,代码中的 "redundant" 只是 switchcase 关键字。你想把他们排除在外吗?因为其余的不是"redundant",他们是必需的。

另请注意,在 Go 中,即使没有 break(与其他语言不同),case 也不会失败,因此在上面的示例中,如果 f.Baznil,你将它设置为42并且f.Qux不会被检查(所以不会返回error),但是如果f.Baz是非nil 并且 f.Quxnil,将返回 error。我知道这只是一个例子,但要记住这一点。如果您使用 switch,您应该首先处理 error!或者使用 if 语句,然后无论字段检查的顺序如何,都会检测并返回错误。

您使用 switch 编写的代码简洁高效。如果你想让它不那么冗长,可读性(和性能)就会受到影响。

您可以使用辅助函数来检查指针值是否为 nil:

func n(i interface{}) bool {
    v := reflect.ValueOf(i)
    return v.Kind() == reflect.Ptr && v.IsNil()
}

并使用它:

func check(f *Foo) error {
    switch {
    case n(f.Bar):
        return errors.New("Missing 'bar'")
    case n(f.Qux):
        return errors.New("Missing 'qux'")
    case n(f.Baz):
        x := int64(42)
        f.Baz = &x
    }
    return nil
}

或使用 if 语句:

func check2(f *Foo) error {
    if n(f.Bar) {
        return errors.New("Missing 'bar'")
    }
    if n(f.Qux) {
        return errors.New("Missing 'qux'")
    }
    if n(f.Baz) {
        x := int64(42)
        f.Baz = &x
    }
    return nil
}

Go Playground 上试试这些。