Clearing up some of my confusions about Closures

โš“ Rust    ๐Ÿ“… 2025-06-21    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 6      

surdeus

Warning

This post was published 52 days ago. The information described in this article may have changed.

I'm learning closures for the first time; I find it hard so these below are questions to get a sense of my understanding and hopefully expand/correct it.

First, my summary is:

Trait Executions Move Into Move Out Mutation
FnOnce n<=1 Allowed Allowed Allowed (?)
FnMut n >= 0 Allowed Not Allowed Allowed
Fn n >= 0 Allowed Not Allowed Not Allowed
Source Paragraph (click for more details)

More specifically, taking just:

FnMut applies to closures that donโ€™t move captured values out of their body, but that might mutate the captured values. These closures can be called more than once.

I was confused by the "move in and move out" here. And others too.

Snippets and Questions

Here are some examples I made up and were tricky for me to analyse (alongside questions to get help / guidance with):

  • Example 1
fn main(){
  let x = String::from("hello");
  let move_x_into_closure = move || {
      println!("{}", x);
  };
  move_x_into_closure(); 
  move_x_into_closure();
  // println!("{x}"); // fails, x was moved into the closure.
}

So in this case, the ownership of x is moved into the closure (and out of x). One can still run the function many times.

  • Question 1: It's a bit mysterious to me where is the x stored? (Especially given the following example.)

This one would pass though, since the print only takes a borrow (unless we return or use x;):

fn main(){
  let x = String::from("hello");
  let x_stays_alive_outside_closure = || {
     println!("{}", x);
  };
  x_stays_alive_outside_closure();
  x_stays_alive_outside_closure();
  x;
}
  • Question 2: in both cases above the Trait should be Fn ?Since it does not move ownership out (which I understand as return x or just x in the last expression) , and it does not mutate any variable (just takes an immutable borrow.)

But if one writes instead:

fn main(){
  let x = String::from("hello");
  let move_in_out = move || {
     println!("{}", x);
     x
  };
  move_in_out();
//   move_in_out();
//   x;
}
  • Question 3: Now it's FnOnce ? So uncommenting fails.

3 posts - 2 participants

Read full topic

๐Ÿท๏ธ rust_feed