我可以将must_use应用于函数结果吗?

9

我有一个返回 f64 的函数。我想确保使用该函数的输出,而不是只忽略它。有没有办法做到这一点?

返回类型不用于错误处理,因此将其包装在 ResultOption 中并没有真正意义。

我希望得到类似于以下代码的结果:

#[must_use]
fn calculate_the_thing(number: f64) -> f64 {
    number * 2.0
}
2个回答

18
自 Rust 1.27 版本起,#[must_use] 属性可以用于函数
#[must_use]
fn calculate_the_thing(number: f64) -> f64 {
    number * 2.0
}

fn main() {
    calculate_the_thing(4); // warning: unused return value of `calculate_the_thing ` which must be used

    let _ = calculate_the_thing(4); // (no warning)
}

在旧版本中,#[must_use] 只适用于类型,而不是单个值。
一个替代方法是定义一个简单的包装类型,它是 #[must_use]:
#[must_use = "this value should be used (extract with .0)"]
pub struct MustUse<T>(pub T);

你的函数可以返回MustUse<f64>,如果用户写calculate_the_thing(12.3),他们将会得到一个警告,甚至会建议正确的方法去获取他们想要的东西:let x = calculate_the_thing(12.3).0;例如
fn calculate_the_thing(number: f64) -> MustUse<f64> {
    MustUse(number * 2.0)
}

fn main() {
    calculate_the_thing(12.3); // whoops
    
    let x = calculate_the_thing(12.3).0;
    println!("{}", x);
}

warning: unused `MustUse` which must be used: this value should be used (extract with .0)
 --> src/main.rs:9:5
  |
9 |     calculate_the_thing(12.3); // whoops
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(unused_must_use)] on by default

提取时加上“.0”——这是我没有预料到的一点巧妙之处。非常酷! - Shepmaster
2
如果从Write::write返回的写入字节数是must_use而不仅仅是它所包装的Result,那就太好了。忽略这一点,并假设所有数据都已被写入,很可能会导致间歇性错误。 - poolie
悲伤。RFC 886本来会很棒的 - (实际上这就是我在寻找的)。 :( - U007D

11

是的,您可以通过 RFC 1940 和 Rust 1.27 开始提供的功能实现,而无需更改原始代码:

#[must_use]
fn calculate_the_thing(number: f64) -> f64 {
    number * 2.0
}

fn main() {
    calculate_the_thing(21.0);
}
warning: unused return value of `calculate_the_thing` which must be used
 --> src/main.rs:7:5
  |
7 |     calculate_the_thing(21.0);
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: #[warn(unused_must_use)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.71s
     Running `target/debug/playground`

2
你知道为什么函数不默认使用must_use注释吗?Swift的行为相反:当不想对函数的返回类型进行任何操作时,我们必须显式地用@discardableResult注释函数(否则会有警告)。这比Rust的方法更加无误。创建带有返回类型的函数时,我认为函数的创建者很可能希望调用者对结果做些什么。添加must_use注释会增加很多噪音和维护痛苦。 - J. Doe
当没有返回值时,不期望有任何东西被返回。当返回一个值而它没有被分配给任何东西时,我认为 Rust 的处理方式很奇怪:'哦,没什么好看的',必须添加注释才能产生任何警告。我无法想象在任何情况下 Rust 处理未分配值的方式比 Swift 更加无误(Swift 的风格是:调用函数时不分配值始终会发出警告,但你可以通过添加 @discardableResult 显式地选择退出(据我所知,这种情况非常罕见))。 - J. Doe
我认为这样做更好。因为调用者有权丢弃他不需要的东西。此外,函数的作者会有意识地决定该值是否重要,以便使用警告。例如,一个只在某种方式下使用结果时才执行某些操作的惰性函数。在这种情况下,作者知道并标记函数或类型为must_use。另一方面,add函数可能返回一个确认布尔值,用户可能不需要。用户不需要考虑值是否被使用,这取决于用户。 - RedCrafter LP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接