book icon indicating copy to clipboard operation
book copied to clipboard

chapter 13 about FnOnce clousure definition

Open llianc62 opened this issue 1 year ago • 1 comments
trafficstars

URL to the section(s) of the book with this problem: https://doc.rust-lang.org/book/ch13-01-closures.html#moving-captured-values-out-of-closures-and-the-fn-traits

  1. FnOnce applies to closures that can be called once. All closures implement at least this trait, because all closures can be called. A closure that moves captured values out of its body will only implement FnOnce and none of the other Fn traits, because it can only be called once.
  2. 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.
  3. Fn applies to closures that don’t move captured values out of their body and that don’t mutate captured values, as well as closures that capture nothing from their environment. These closures can be called more than once without mutating their environment, which is important in cases such as calling a closure multiple times concurrently.

A closure that moves captured values out of its body will only implement FnOnce

I thought it could be: A closure that moves captured values in of its body will only implement FnOnce ?

in or out?

llianc62 avatar Aug 15 '24 07:08 llianc62

Like this :

let x = String::from("hello");
let consume_x = move || {
    println!("{}", x);
};
consume_x(); // closure take the ownership
// consume_x(); // can not execute because `x` is moved

llianc62 avatar Aug 15 '24 07:08 llianc62

This is a tricky one, but the terminology here is correct. If you try running the code you showed, it works just fine! Here’s a playground which demonstrates that. (Also notice that println! borrows its argument here!) Your code does move ownership into the closure, but it does not moves it out. That means your example implements Fn as well as FnOnce.

If you returned the value from the closure at the end, like this, however, it would only implement FnOnce, because the value would have been moved out of the closure, just as the text says:

let x = String::from("hello");
let consume_x = move || {
    println!("{}", x);
    x
};
consume_x(); // closure take the ownership
consume_x(); // can not execute because `x` is moved

This has the error you expected from the println example (playground)

There are two main ways to move a value out of a closure: returning it, or passing it to a function which takes ownership of it.

Hope that helps!

chriskrycho avatar Sep 30 '24 17:09 chriskrycho