Reputation: 10156
I can use the #[must_use]
attribute to mark a function as having a return value that must either be used or explicitly ignored:
#[must_use]
fn plain() -> i32 {
1
}
fn main() {
plain(); // warning
}
However, if I want to change my function so it now returns a Result
, I cannot do this:
#[must_use]
fn result() -> Result<i32, ()> {
Ok(1)
}
fn main() {
result().unwrap();
}
because the call to .unwrap()
counts as a "use", and the #[must_use]
attribute is applying to the entire Result
.
Is there a way to make #[must_use]
apply to the inner type as well? Essentially I would like to make sure that the i32
is not accidentally "eaten" by the semicolon.
I have the additional constraint that I cannot change the public API of this function, so I can't make it return a Result<MustUse<i32>, ()>
or something along those lines.
Upvotes: 3
Views: 753
Reputation: 169018
You can't do this by directly adding your own annotation to the Result
, but you can do this trivially with a newtype:
#[must_use]
#[repr(transparent)]
pub struct MustUse<T>(T);
impl<T> From<T> for MustUse<T> {
fn from(v: T) -> Self {
Self(v)
}
}
impl<T> MustUse<T> {
#[must_use]
fn into_inner(self) -> T {
self.0
}
}
Now, given this declaration:
fn result() -> Result<MustUse<i32>, ()> {
Ok(1.into())
}
All of the following cause a warning:
result();
warns because Result<_, _>
is must-use.result().unwrap();
warns because MustUse<_>
is must-use.result().unwrap().into_inner();
warns because MustUse<_>::into_inner()
is must-use.(Note that you can bypass the warning by invoking a different, non-must-use method of Result
, such as result().ok()
, but that will be true no matter what you do.)
Upvotes: 5