Rust's .expect()是结果/选项空间中最令人惊讶的名字之一.虽然unwrap是有意义的——通过"展开"从Result中获得一个值——但expect(对我来说)出乎意料地违反直觉.

由于Rust的灵感来自函数式编程语言的约定,我一直认为这是另一个"奇怪的默默无闻致敬"的例子,但当我问Duck时,它找不到我的答案.

所以,我放弃了.为什么.expect()是Rust的.unwrap_or_panic_with_this_message()函数的名字?这是对另一种功能性语言中的功能的引用吗?它是Tcl的反向阴影(或补充)?是因为Mozilla有太多的深夜和太多的Espresso ?

这个勇敢(但凶猛)的词源是什么标准图书馆的小成员?

推荐答案

Summary:

没有给出该名称的明确原因.然而,这个名字极有可能来自世界parsers,人们"期望"看到一个特定的标记(否则编译失败).

在rustc中,expect个类似函数的使用早于Option个函数的使用.这些函数包括expect(p, token::SEMI),用于解析分号,expect_word(p, "let"),用于解析let关键字.如果未达到预期,编译将失败并显示错误消息.

最终,在编译器中添加了一个实用函数,该函数期望的不是特定的令牌或字符串,而是给定的Option包含一个值(否则,使用给定的错误消息编译失败).随着时间的推移,它被转移到Option struct 本身,至今仍保留在那里.

就我个人而言,我觉得这一点都不奇怪.它只是另一个动词,你可以把它和对象联系起来,比如展开、获取或映射它的值.从你的Option中期待一个值(否则,失败)似乎很自然.


History:

最早的提交记录如下:

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

这将在编译器中添加此函数:

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

据我所知,这是第一个名为"expect"的函数,用于判断Option.请特别注意commit中的这个示例用例(它实现了对类方法的支持!):

#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)});

如果decoder::maybe_find_item的结果是None,编译将失败,并出现给定的错误.

我鼓励您在这个提交中查看解析器代码——还有其他expect个类似函数的广泛使用:例如expect(p, token::RPAREN)expect_word(p, "let").在这种环境下,这个新函数的名称几乎显而易见.

最终,该函数的实用性被提取出来,并放在Option本身中:

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

看起来像:

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; } }
}

值得注意的是,不久之后,终于有了一个名为unwrap_expect的(附加)函数:

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)
}

随着时间的推移,它们都被Expect trait所包含,Option实现了:

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;
}

剧透:这种trait 已经不存在了.根据以下内容,它很快被移除:

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

这或多或少就是我们今天的处境.

我认为最有可能的结论是,expect作为一个有意义的函数名的使用早于Option年.考虑到它所做的(期望值或失败),几乎没有理由打破这种模式.

Rust相关问答推荐

为什么父作用域中的变量超出了子作用域

如何容器化Linux上基于Rust的Windows应用程序的编译过程?

MacOS(AARCH64)上Ghidra中的二进制补丁导致进程终止

如何导出 rust 色二进制文件中的符号

新创建的变量的绑定生存期

原始数组数据类型的默认trait实现

重写Rust中的方法以使用`&;mut self`而不是`mut self`

对于已经被认为是未定义行为的相同数据,纯粹存在`&;[u32]`和`&;mut[u32]`吗?

Trait bound i8:来自u8的不满意

从未排序的链表中删除重复项的铁 rust 代码在ELSE分支的低级上做了什么?

为什么`AlternateScreen`在读取输入键时需要按Enter键?

Rust 中什么时候可以返回函数生成的字符串切片&str?

UnsafeCell:它如何通知 rustc Select 退出基于别名的优化?

Rust中的一生语法有什么作用?

如何在Rust中使用Serde创建一个自定义的反序列化器来处理带有内部标记的枚举

使用 Rust 从 Raspberry Pi Pico 上的 SPI 读取值

改变不实现克隆的 dioxus UseState struct

TinyVec 如何与 Vec 大小相同?

传递 Option<&mut T> 时何时需要 mut

当值是新类型包装器时,对键的奇怪 HashMap 生命周期要求