web-dev-qa-db-ja.com

成功した場合に結果が返されない関数からエラーを返す慣用的な方法は何ですか?

Rustでは、回復可能なエラーに対処する慣用的な方法はResultを使用することだと思います。たとえば、この関数は明らかに慣用的です。

fn do_work() -> Result<u64, WorkError> {...}

もちろん、単一の明白な障害状態を持つ関数もあるため、代わりにOptionタイプを使用します。慣用的な例は次のようになります:

fn do_work() -> Option<u64>

これはすべて、ドキュメントで簡単に説明されています。ただし、関数が失敗する可能性があるが、成功した場合に意味のある値が得られない場合について混乱しています。次の2つの機能を比較します。

fn do_work() -> Option<WorkError>
// vs
fn do_work() -> Result<(), WorkError>

これらのうちどれがより慣用的であるか、または現実の世界でより頻繁に使用されているかわかりませんRustコード。このような質問の主なリソースはRustの本ですが、「 エラー処理 」のセクションでは対処されていないと思います。他のRust =ドキュメントのいずれか。

もちろん、これはかなり主観的に思えますが、私はどちらの形式が慣用的であるか、またはなぜ1つの形式が他の形式より優れている(または劣っている)かを示す信頼できる情報源を探しています。 (また、GoやHaskellのように、「エラーを値として使用する」言語を多用する他の言語との比較についても知りたいです。)

31
Others

fn do_work() -> Result<(), WorkError>を使用します。

Result<(), WorkError>は、作業を完了させたいが、失敗する可能性があることを意味します。

_Option<WorkError>_は、エラーを取得したいが、存在しない場合があることを意味します。

do_work()を作成するときに、作業を実行してもエラーが発生しないようにしたい場合があるので、Result<(), WorkError>の方が適しています。

_Option<WorkError>_はfn get_last_work_error() -> Option<WorkError>のような場合にのみ使用されると思います。

26
WiSaGaN

Rustは「かなり強く型付けされています」(そして、言語がどれほど強く型付けされているかを測定する方法について私に声をかけないでください...)。これは、Rustは通常、タイプを「発話」させてコードを文書化するためのツールを提供するという意味で、したがって、この機能を使用して可読コードを記述することは慣用的です。

言い換えれば、あなたが尋ねている質問は、「どのタイプがそのシグネチャを読む誰にとっても関数が何をするのに最も適しているのか」ということです。

Result<(), Workerror>の場合、ストレートに表示されます ドキュメントから

結果は、成功(Ok)または失敗(Err)を表すタイプです。

つまり、あなたのケースに特化して、それはあなたの関数が成功した場合は何も返さないことを意味します(Ok<()>で表される)、またはエラーがある場合はWorkError(_Err<WorkError>_)。これは、質問で関数を説明した方法をコードで直接表現したものです。

これを_Option<WorkError>_またはOption<()>と比較します

タイプOptionはオプションの値を表します。すべてのOptionはSomeで値を含むかNoneであり、

あなたの場合、_Option<WorkError>_は読者に「この関数はWorkErrorを返す必要がありますが、何も返さない可能性があります」と言っています。 「何も返さない」ケースは、関数が実際に成功したことを意味することを文書化できますが、型だけからはそれほど明白ではありません。

Option<()>は、「この関数は何も返さないか、意味のある戻り値を返さない可能性があります」と言います。これは、WorkErrorに他の情報(エラータイプやエラーメッセージなど)が含まれていない場合に言うと合理的です。そしてそれは実際には「エラーが発生しました」と言う唯一の方法です。この場合、単純なboolは同じ情報を保持します...それ以外の場合、Resultを使用すると、エラーに関連するいくつかの詳細情報を返すことができます。

6
Paolo Falabella