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
}

私が見つけた唯一の回避策は、*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、初期化せずに使用できます。独自の方法でゼロにされます。呼び出し元の関数がこの値を使用することは想定されていないため、私はあまり気にしません。

4

7 に答える 7

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

これ、あなたの3番目の例も大丈夫だと思います。理解されているルールは、関数がエラーを返す場合、ドキュメントで明確に説明されていない限り、他の戻り値が意味のある値を持つことを信頼することはできないということです。したがって、ここでおそらく無意味な構造体の値を返すことは問題ありません。

于 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

構造体を返す代わりに考えられる方法として、呼び出し元に構造体と関数setparamsを割り当てさせることを検討してください。

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

私にとって、私はあなたの2番目のオプションを好みます。

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

このようにして、エラーが発生したときに、canFail()呼び出し元がcardnilであるために使用できないようにすることができます。発信者が最初にエラーをチェックすることを確認することはできません。

于 2019-02-01T09:46:22.157 に答える
1

peterSOの答えが最も近いですが、私が使用するものとはまったく異なります。私はこれが最善だと思います:

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

まず、リターンに使用できるように、ポインタを使用していませんnil。これは巧妙なトリックだと思いますが、実際にstructポインタである必要がない限り(変更やその他の理由で)、値を返す方が適切です。また、次のように、戻り値を使用していない限り、戻り値に名前を付ける必要はないと思います。

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

それは2つの理由で問題があります。まず、その時点での変数が何であれ、戻り値を単純に設定できる状況になるとは限りません。第二に、より大きな関数を使用している場合、可変シャドウエラーが発生するため、より深いレベルでネイキッドリターンを使用することはできません。

最後に、または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

于 2021-02-10T19:32:57.900 に答える
0

あなたの関数が他の誰かのように振る舞わない場合、その署名、IE、で読むことを想定しますif an error has occurred I should ignore the value along it

とほとんど同じようio.Readern>0error

次に、それを文書化して、エラーに沿った戻り値に関して何を考慮すべきかをユーザーに説明する必要があります。

署名を変更することで、このような場合の一般的なAPI関係は、まれですが避けられないことではありません。

代わりに、関数の動作を適切に文書化する必要があります。

于 2021-09-17T09:14:45.047 に答える