21

我有一个函数,它返回Card一个struct类型,或者一个错误。

问题是,发生错误时如何从函数返回?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
}

我发现的唯一解决方法是使用 a*Card而不是 a Card, a 在出现错误时使用它,或者在没有错误发生时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是一个命名的返回值,我可以在不初始化的情况下使用它。它以自己的方式归零,我真的不在乎,因为调用函数不应该使用这个值。

4

7 回答 7

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

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

于 2013-03-11T12:38:45.320 回答
6

例如,

type Card struct {
}

func canFail() (card Card, err error) {
    return Card{}, errors.New("not yet implemented")
}
于 2013-03-11T10:21:41.677 回答
3
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
}
于 2013-03-11T10:21:50.137 回答
1

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

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

于 2017-02-03T16:46:43.010 回答
1

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

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

首先,它没有使用指针,所以它可以nil用于返回。我认为这是一个巧妙的技巧,但除非你真的需要struct成为一个指针(出于修改或其他原因),否则返回一个值会更好。此外,我认为不应命名返回值,除非您正在使用它们,如下所示:

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

这是有问题的,原因有两个。首先,您并不总是处于可以简单地将返回值设置为当时该变量的任何情况的情况。其次,如果你有一个更大的函数,你将无法在更深层次使用裸返回,因为你会得到可变阴影错误。

最后,使用Card{}代替nilorcard更冗长,但它可以更好地传达您正在做的事情。如果您使用以下任何一种:

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

于 2021-02-10T19:32:57.900 回答
1

对我来说,我更喜欢你的第二种选择。

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

这样你可以确保当错误发生时,canFail()调用者将无法使用它,card因为它是 nil。我们不能确保调用者会首先检查错误。

于 2019-02-01T09:46:22.157 回答
0

如果您的函数的行为不像其他人会假设读取其签名 IE if an error has occurred I should ignore the value along it,.

很像 any io.Reader,它可能会返回n>0一个error

然后,您应该简单地记录它以向用户解释关于错误中的返回值应该考虑什么。

改变签名,因此一般的 API 关系,对于这种情况,罕见但并非不可避免,不是 Go 的方法。

相反,您应该充分记录函数的行为。

于 2021-09-17T09:14:45.047 回答