Function core::hint::must_use

const: unstable · source ·
pub fn must_use<T>(value: T) -> T
🔬This is a nightly-only experimental API. (hint_must_use #94745)
Expand description

如果调用者未使用给定值 (返回、存储在变量中等),则会触发 unused_must_use 警告的标识函数。

这主要用于宏生成的代码,其中类型或函数上的 #[must_use] 属性 不方便。

Example

#![feature(hint_must_use)]

use core::fmt;

pub struct Error(/* ... */);

#[macro_export]
macro_rules! make_error {
    ($($args:expr),*) => {
        core::hint::must_use({
            let error = $crate::make_error(core::format_args!($($args),*));
            error
        })
    };
}

// make_error 的实现细节! macro.
#[doc(hidden)]
pub fn make_error(args: fmt::Arguments<'_>) -> Error {
    Error(/* ... */)
}

fn demo() -> Option<Error> {
    if true {
        // 哎呀,本来想写 `return Some(make_error!("..."));`
        Some(make_error!("..."));
    }
    None
}
Run

在上面的示例中,我们希望 unused_must_use lint 应用于 make_error! 创建的值。 但是,结构体上的 #[must_use] 和函数上的 #[must_use] 都不适用于这里,因此宏使用 core::hint::must_use 进行扩展。

  • 我们不希望在 struct Error 上使用 #[must_use],因为这会使以下无问题的代码触发警告:

    fn f(arg: &str) -> Result<(), Error>
    
    #[test]
    fn t() {
        // 如果传递一个空字符串,则断言 `f` 将返回错误。
        // 这里没有使用 `Error` 类型的值,但这不是问题。
        f("").unwrap_err();
    }
    Run
  • fn make_error 上使用 #[must_use] 无济于事,因为返回值 is 被用作 let 语句的右侧。 let 语句看起来毫无用处,但实际上对于确保 format_args 扩展中的临时对象在创建 Error 之后不会保持活动状态是必要的,因为在创建 Error 之后保持它们活动可能会导致异步代码中的 autotrait 问题:

    async fn f() {
        // 在 make_error 扩展中使用 `let` 会导致诸如 `unsync()` 之类的临时变量在 `let` 语句的分号处,该分号位于 await 点之前。
        // 否则它们会一直停留在 *this* 语句的分号上,也就是在 await 点之后,并且封闭的 Future 不会实现 Send。
        log(make_error!("look: {:p}", unsync())).await;
    }
    
    async fn log(error: Error) {/* ... */}
    
    // 返回没有 Sync impl 的内容。
    fn unsync() -> *const () {
        0 as *const ()
    }
    Run