在go中,返回结构或错误的惯用方法是什么?

时间:2013-03-11 10:12:57

标签: error-handling go zero

我的函数返回Cardstruct类型或错误。

问题是,如何在发生错误时从函数返回? nil对结构无效,我的Card类型没有有效的零值。

func canFail() (card Card, err error) {
    // return nil, errors.New("Not yet implemented"); // Fails
    return Card{Ace, Spades}, errors.New("not yet implemented"); // Works, but very ugly
}

我找到的唯一解决方法是使用*Card而不是Card,在出现错误时将其设为nil或将其指向实际Card当没有错误发生时,那是非常笨拙的。

func canFail() (card *Card, err error) {
    return nil, errors.New("not yet implemented");
}

有更好的方法吗?

编辑:我找到了另一种方式,但不知道这是不是惯用的,甚至是好的风格。

func canFail() (card Card, err error) {
    return card, errors.New("not yet implemented")
}

由于card是一个命名的返回值,我可以在不初始化的情况下使用它。它以自己的方式归零,我并不在乎,因为调用函数不应该使用这个值。

7 个答案:

答案 0 :(得分:13)

func canFail() (card Card, err error) {
    return card, errors.New("not yet implemented")
}

我认为这是你的第三个例子,也很好。理解的规则是当函数返回错误时,除非文档另有说明,否则不能依赖其他返回值来获得有意义的值。所以在这里返回一个可能没有意义的结构值是很好的。

答案 1 :(得分:5)

例如,

type Card struct {
}

func canFail() (card Card, err error) {
    return Card{}, errors.New("not yet implemented")
}

答案 2 :(得分:5)

func canFail() (card Card, err error) {
        if somethingWrong {
                err = errors.New("Not yet implemented")
                return
        }

        if foo {
                card = baz
                return
        }

        ... 

        // or 
        return Card{Ace, Spades}, nil
}

答案 3 :(得分:2)

作为返回结构的一种可能的替代方法,您可以考虑让调用者分配它并将函数设置为params。

func canFail(card *Card) (err error) {
    if someCondition {
        // set one property
        card.Suit = Diamond

        // set all at once
        *card = Card{Ace, Spade}
    } else {
        err = errors.New("something went wrong")
    }

    return
}

如果您不方便假装Go支持C ++样式引用,您还应该检查card是否为nil

https://play.golang.org/p/o-2TYwWCTL

答案 4 :(得分:1)

对于我来说,我更喜欢您的第二个选择。

func canFail() (card *Card, err error) {
    return nil, errors.New("not yet implemented");
}

这样,您可以确保在发生错误时,canFail()调用者将无法使用card,因为它为空。我们无法确保调用者将首先检查错误。

答案 5 :(得分:1)

peterSO 答案是最接近的,但它不是我会使用的。我认为这 最好:

func canFail() (Card, error) {
   return Card{}, errors.New("not yet implemented")
}

首先,它不使用指针只是为了使用 nil 返回。我认为 这是一个巧妙的技巧,但除非您确实需要 struct 作为指针 (出于修改或其他原因),然后返回一个值更好。我也不 认为应该命名返回值,除非您正在使用它们,例如 这个:

func canFail() (card Card, err error) {
   return
}

这是有问题的,原因有两个。首先,你并不总是会在 在这种情况下,您可以简单地将返回值设为任何变量 是在那个时候。其次,如果你有一个更大的功能,你将无法使用 更深层次的赤裸裸的回报,因为你会得到可变的阴影错误。 最后,使用 Card{} 而不是 nilcard 更冗长,但更好 传达你正在做的事情。如果您使用其中任何一个:

return
return card, err

如果没有上下文就不清楚函数是否成功,而这个:

return Card{}, err

很明显该函数失败了。它与您将使用的模式相同 原始类型:

return false, err
return 0, err
return '\x00', err
return "", err
return []byte{}, err

https://github.com/golang/go/wiki/CodeReviewComments#pass-values

答案 6 :(得分:0)

我建议您使用指针而不是类型,因为如果遇到任何错误,它会创建该类型的空对象。而是返回类型的指针,并在出现错误时返回nil。

{{1}}