I have a question about the correction of [clippy::redundant-closure]

I am very sorry, but the above warning did not occur before rustc version 1.74.0,
I have responded after my own investigation.
The following is the content of my investigation.

I have also checked similar posts.

[ Unsure how to fix Clippy warning: Redundant Closure](Unsure how to fix Clippy warning: Redundant Closure)

Thank you in advance.

1 Like

The suggestion can be hard to understand when you’ve never seen this particular style of providing a closure/function argument to an API such as for_each.

The basic idea is that |s| printer(s) is a closure/function with a single argument s and the behavior like calling printer(s). The same thing already holds true for printer itself. The call thus can be made without declaring a new, sort-of “wrapping”, closure at all:

-   streamer.iter().for_each(|s| printer(s));
+   streamer.iter().for_each(printer);

Importantly, this only works if you dare to write “printer” without trying to pass an argument to it, which is why your attempts to write ….for_each(printer(&s)) failed. Closures and functions cannot only be used for calling them, like “f(x)”, but the name of a variable holding a closure, or of a function, itself, like just “f”, can be evaluated as well, resulting in a value of the corresponding closure or function type.

1 Like

In case you’re interested in more even idiomatic code (at least in my view):

I would typically avoid this style of code

let f = |arg: &Type| {
    // body…
    // body…
};
something.for_each(f);

and instead just write the closure directly in the for_each call:

something.for_each(|arg| {
    // body…
    // body…
});

This has the additional benefit that the type signature becomes unnecessary, since the compiler can better infer the types for immediately provided closure expressions in a for_each like that.

In your code, you can also avoid the extra step of cloning the Strings for the purpose of printing them.

    streamer.iter().for_each(|s| {
        println!(
            "{}{}{} Liked♡",
            s.name.as_deref().unwrap_or_default(),
            s.mark.as_deref().unwrap_or_default(),
            s.x_name.as_deref().unwrap_or_default()
        )
    })

A call to s.name.as_deref() produces a Option<&str>, then unwrap_or_default() produces a &str, everything without additional cloning or allocation. Instead of concatenating one string and then printing it, you can just have the 3 parts directly appear after each other in the println call, with 3 formatting placeholders {}{}{}.

Even in cases where you do want to produce an owned string, at least the second and third part don’t need to look like s.mark.clone().unwrap_or_default().as_str(), which also produces a &str, when s.mark.as_deref().unwrap_or_default() can do it more efficiently.

4 Likes

Yes, I understood it because it is a common way of writing in the Scala language.

The above description in the screenshot is an error in the process of modification.
We apologize for the confusion.

Thank you for your in-depth discussion, advice, and even providing examples.
I cannot thank you enough.
We would like to make a correction and post the corrected code here after transcribing it to the ISSUE you created.