
Description
The intent of the filter_map
method is to unwrap element values and skip None
s when iterating over elements that are Option
s. It's not a universal shorthand for filter
followed by a call tomap
. The filter_map
documentation indicates this.
The current implementation of the fliter_map
lint triggers on every call to filter
followed by a call tomap
and basically notes that the suggestion can make the code more complicated as a known issue. It encourages changes like this (from #3186):
extra_args
.split("__CLIPPY_HACKERY__")
.filter(|s| !s.is_empty())
.map(str::to_owned)
to
extra_args
.split("__CLIPPY_HACKERY__")
.filter_map(|s| if s.is_empty() {
None
} else {
Some(s.to_string())
})
I find the final code is less readable and more complicated than the code at the start. Although, there is one less function call, there is now an if
statement and extra code for constructing an option.
Let's change the lint to only trigger in the following conditions. In the table below option_expr
is an expression with type Option<_>
and result_expr
is an expression with type Result<_, _>
.
Code | Suggestion |
---|---|
filter(|x| option_expr.is_some()).map(|x| x.unwrap()) |
filter_map(|x| option_expr) |
filter(|x| option_expr.is_some()).flat_map(|x| x) |
filter_map(|x| option_expr) |
filter(|x| result_expr.is_ok()).map(|x| x.unwrap()) |
filter_map(|x| result_expr.ok()) |