The intent of the filter_map method is to unwrap element values and skip Nones when iterating over elements that are Options. 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()) |
The intent of the
filter_mapmethod is to unwrap element values and skipNones when iterating over elements that areOptions. It's not a universal shorthand forfilterfollowed by a call tomap. Thefilter_mapdocumentation indicates this.The current implementation of the
fliter_maplint triggers on every call tofilterfollowed by a call tomapand basically notes that the suggestion can make the code more complicated as a known issue. It encourages changes like this (from #3186):to
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
ifstatement and extra code for constructing an option.Let's change the lint to only trigger in the following conditions. In the table below
option_expris an expression with typeOption<_>andresult_expris an expression with typeResult<_, _>.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())