cameron1024
cameron1024

Reputation: 10156

How to make the inner value of a Result must_use

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

Answers (1)

cdhowie
cdhowie

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

Related Questions