rust-clippy icon indicating copy to clipboard operation
rust-clippy copied to clipboard

Improve suggestions for option_map_unit_fn

Open pdolezal opened this issue 5 years ago • 2 comments

The suggestion for option_map_unit_fn could include more details and options for solving the lint.

Let's consider an invocation chain on Option which consumes the value, if any, at the end. Clippy issues the warning for such a piece of code.

give_me_some_iterator()
    .next()
    .filter(|&n| n % 2 == 0)
    .map(|n| n * 2)
    .filter(|&n| n > 100)
    .map(|n| println!("And the winning number is… {}", n));

The lint's suggestion in such situations does not look very appealing. Using if let on the whole statement does not improve readability, IMO. I guess that the next thing to try would be using a helper variable:

let n = give_me_some_iterator()
    .next()
    .filter(|&n| n % 2 == 0)
    .map(|n| n * 2)
    .filter(|&n| n > 100);

if let Some(found) = n {
    println!("And the winning number is… {}", n);
}

Obviously, it breaks the natural chained flow, which does not look very good either. The next step could be:

let _ = give_me_some_iterator()
    .next()
    .filter(|&n| n % 2 == 0)
    .map(|n| n * 2)
    .filter(|&n| n > 100)
    .map(|n| println!("And the winning number is… {}", n));

Although it is close to the original, the assignment feels like a workaround just to mute Clippy. I was pointed out that there is yet another way, which I – as a newbie – would hardly figure out:

give_me_some_iterator()
    .next()
    .filter(|&n| n % 2 == 0)
    .map(|n| n * 2)
    .filter(|&n| n > 100)
    .map_or((), |n| println!("And the winning number is… {}", n));

This is quite nice, but I'm not sure how much idiomatic it is considered or how much known and used it is. There is a topic on Rust Internals with a few more details and a proposal of an extension of Option to express better the intent of consuming the value. Anyway, I think that an improved lint would resolve some concerns shown in the discussion and offer an idiomatic alternative that keeps the original readability and compactness.

pdolezal avatar Oct 22 '20 21:10 pdolezal

@rustbot modify labels: +A-suggestion +L-enhancement

giraffate avatar Oct 27 '20 03:10 giraffate

I do not like this lint either.

Maybe there should be another function (e.g., "apply") that behaves like "map" but does not return a value.

kaimast avatar Oct 08 '24 19:10 kaimast

I think this should be treated the same way as Iterator::for_each -- usually to be avoided in favor of a for-loop, but fine to use if the method chain is a longer one. So maybe this lint should ignore method chains longer than, say, 3 calls (this could be configurable)

ada4a avatar Oct 08 '25 16:10 ada4a