为什么 Rust 的 .expect() 叫做 expect?

agh*_*ast 17 rust

Rust.expect()是 Result/Option 空间中最令人惊讶的名字之一。虽然unwrap有道理——Result通过“解包”从 a 中获取一个值——但expect出奇地违反直觉(对我来说)。

由于 Rust 的大部分内容都受到函数式编程语言约定的启发,我一直假设这是“对默默无闻的奇怪敬意”的另一个例子,但是当我问鸭子时,它无法为我找到答案。

所以,我放弃了。为什么是.expect()Rust.unwrap_or_panic_with_this_message()函数的名称?这是对另一种功能语言中的功能的引用吗?它是 Tcl 的反手阴影(或补充)吗?Mozilla 熬夜太多,Espresso 太多的结果?

标准库中这个勇敢(但凶猛!)的小成员的词源是什么?

GMa*_*ckG 22

Summary:

No explicit reason for the name is given. However, it is incredibly likely the name comes from the world of parsers, where one "expects" to see a particular token (else the compilation fails).

Within rustc, the use of expect-like functions long predate use within Option. These are functions like expect(p, token::SEMI) to expect to parse a semicolon and expect_word(p, "let") to expect to parse the let keyword. If the expectation isn't met, compilation fails with an error message.

Eventually a utility function was added within the compiler that would expect not a specific token or string, but that a given Option contained a value (else, fail compilation with the given error message). Over time this was moved to the Option struct itself, where it remains today.

Personally, I don't find it unusual at all. It's just another verb you can do to the object, like unwrapping or taking or mapping its value. Expecting a value (else, fail) from your Option seems quite natural.


History:

The oldest commit of note is the following:

https://github.com/rust-lang/rust/commit/b06dc884e57644a0c7e9c5391af9e0392e5f49ac

Which adds this function within the compiler:

fn expect<T: copy>(sess: session, opt: option<T>, msg: fn() -> str) -> T {
    alt opt {
       some(t) { t }
       none { sess.bug(msg()); }
    }
}
Run Code Online (Sandbox Code Playgroud)

As far as I can tell, this is the first function named "expect" that deals with inspecting an Option. Observe in particular this example use-case within the commit (which was implementing support for class methods!):

#debug("looking up %? : %?", def, class_doc);
let the_field = expect(tcx.sess,
    decoder::maybe_find_item(def.node, class_doc),
    {|| #fmt("get_field_type: in class %?, field ID %? not found",
             class_id, def)});
Run Code Online (Sandbox Code Playgroud)

If the result of decoder::maybe_find_item is None, compilation will fail with the given error.

I encourage you to look at the parser code in this commit - there is extensive use of other expect-esque functions: e.g., expect(p, token::RPAREN) and expect_word(p, "let"). The name of this new function is almost obvious in this environment.

Eventually, the utility of this function was extracted and placed within Option itself:

https://github.com/rust-lang/rust/commit/e000d1db0ab047b8d2949de4ab221718905ce3b1

Which looked like:

pure fn expect<T: copy>(opt: option<T>, reason: str) -> T {
    #[doc = "
    Gets the value out of an option, printing a specified message on failure
    # Failure
    Fails if the value equals `none`
    "];
    alt opt { some(x) { x } none { fail reason; } }
}
Run Code Online (Sandbox Code Playgroud)

It's worth noting that sometime later, there was eventually an (additional) function named unwrap_expect added in:

https://github.com/rust-lang/rust/commit/be3a71a1aa36173ce2cd521f811d8010029aa46f

pure fn unwrap_expect<T>(-opt: option<T>, reason: ~str) -> T {
    //! As unwrap, but with a specified failure message.
    if opt.is_none() { fail reason; }
    unwrap(opt)
}
Run Code Online (Sandbox Code Playgroud)

Over time these were both subsumed by an Expect trait, which Option implemented:

https://github.com/rust-lang/rust/commit/0d8f5fa618da00653897be2050980c800389be82

/// Extension trait for the `Option` type to add an `expect` method

// FIXME(#14008) should this trait even exist?
pub trait Expect<T> {
    /// Unwraps an option, yielding the content of a `Some`
    ///
    /// # Failure
    ///
    /// Fails if the value is a `None` with a custom failure message provided by
    /// `msg`.
    fn expect<M: Any + Send>(self, m: M) -> T;
}
Run Code Online (Sandbox Code Playgroud)

Spoiler for that TODO: that trait no longer exists. It was removed shortly after per:

https://github.com/rust-lang/rust/issues/14008.

More or less this is where we are at today.

I think the most likely conclusion is that the use of expect as a meaningful function name long predates its use in Option. Given it says what it does (expect a value or fail) there is little reason to break the pattern.

  • 这是一些很棒的侦查。 (3认同)