如果成功,从没有结果的函数返回错误的惯用方法是啥?

Posted

技术标签:

【中文标题】如果成功,从没有结果的函数返回错误的惯用方法是啥?【英文标题】:What is the idiomatic way to return an error from a function with no result if successful?如果成功,从没有结果的函数返回错误的惯用方法是什么? 【发布时间】:2016-08-21 01:20:32 【问题描述】:

在 Rust 中,我认为处理可恢复错误的惯用方法是使用 Result。例如这个函数显然是惯用的:

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

当然,也有一些函数具有单一的、明显的失败状态,因此使用 Option 类型来代替。一个惯用的例子是这样的:

fn do_work() -> Option<u64>

这一切都在文档中直接解决。但是,我对函数可能失败但成功时没有意义的情况感到困惑。比较以下两个函数:

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

我只是不确定其中哪一个更惯用,或者在现实世界的 Rust 代码中更常用。对于此类问题,我的首选资源是 Rust 书,但我认为它的“Error Handling”部分没有解决这个问题。我对任何其他 Rust 文档也没有太多运气。

当然,这似乎很主观,但我正在寻找权威来源,要么说明哪种形式是惯用的,要么说明为什么一种形式优于(或低于)另一种形式。 (我也很好奇该约定与其他大量使用“错误作为值”的语言相比如何,例如 Go 和 Haskell。)

【问题讨论】:

我属于Result&lt;(), Error&gt; 的一方。我通常也将这些别名为我自己的类型。我很想听听别人怎么说。不过我这样做是因为 try! 宏仍然可以很好地配合它。 【参考方案1】:

Rust 是“非常强类型化的”(请不要告诉我我如何衡量一种语言的强类型化程度......)。我的意思是说,Rust 通常为您提供让类型为您“说话”并记录您的代码的工具,因此使用此功能编写可读代码是惯用的。

换句话说,您要问的问题应该是“哪种类型最能代表函数对读取其签名的任何人的作用?”

对于Result&lt;(), Workerror&gt;你可以直接看到from the docs

Result 是表示成功(Ok)或失败(Err)的类型

因此,专门针对您的情况,这意味着您的函数在成功时不返回任何内容(由Ok&lt;()&gt; 表示)或在出现错误时返回WorkError (Err&lt;WorkError&gt;)。这是您在问题中描述函数的方式的代码中非常直接的表示。

将此与Option&lt;WorkError&gt;Option&lt;()&gt; 进行比较

Type Option 表示一个可选值:每个 Option 要么是 Some 并且包含一个值,要么是 None,并且没有

在你的情况下,Option&lt;WorkError&gt; 会对读者说“这个函数应该返回一个 WorkError 但它可能什么也不返回”。您可以记录下“不返回任何内容”的情况意味着该函数实际上是成功的,但这仅从类型上并不是很明显。

Option&lt;()&gt; 说“这个函数可以不返回任何内容或没有任何有意义的返回”,如果WorkError 不包含其他信息(如错误类型或错误消息)并且实际上只是一种说“发生错误”的方式。在这种情况下,一个简单的bool 携带相同的信息...否则Result 允许您返回与错误相关的更多信息。

【讨论】:

【参考方案2】:

使用fn do_work() -&gt; Result&lt;(), WorkError&gt;

Result&lt;(), WorkError&gt; 表示你希望工作完成,但它可能会失败。

Option&lt;WorkError&gt; 表示你想得到一个错误,但它可能不存在。

do_work() 时,您可能希望工作完成但又不想出错,因此Result&lt;(), WorkError&gt; 是更好的选择。

我希望Option&lt;WorkError&gt; 仅用于fn get_last_work_error() -&gt; Option&lt;WorkError&gt; 之类的情况。

【讨论】:

我不认为我不同意,我认为 Result 稍微好一点。但是,我想知道是否有任何“官方”资源以任何方式支持您的回答? @Others 因为do_work 本身就是一个概念性的例子,我不认为会有任何官方约定。但是你可以对标准库中的成语有所了解,例如:doc.rust-lang.org/nightly/std/io/… @Others 当一个可能失败的操作没有返回任何有用的东西(例如std::iostd::fs 的许多函数)时,整个标准库普遍使用Result&lt;(), _&gt;。这是正确的选择。 @Others,使用 Result 在 aturon.github.io/errors/signaling.html#obstructions 得到正式认可(根据 RFC 236)。 @ArtemGr 请注意,该页面中讨论的替代方案将是 OP 问题上下文中的 Option&lt;()&gt;,而不是 Option&lt;WorkError&gt;。前者None 表示工作未正常完成,而后者None 表示工作正常。

以上是关于如果成功,从没有结果的函数返回错误的惯用方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

合并两种错误类型最惯用的方法是啥?

在 JavaScript 中处理非法参数的惯用方法是啥?

从没有参数的函数返回整数数组[重复]

处理在多个 for 循环中声明的变量的最惯用方法是啥? [关闭]

ASSERT(SUCCEEDED(hr))是啥意思

测试 256 位 YMM AVX 寄存器为零的最有效/惯用方法