Summary

Implement

実装する
Clone and Copy for closures where possible:

#![allow(unused)] fn main() { // Many closures can now be passed by-value to multiple functions: fn call<F: FnOnce()>(f: F) { f() } let hello = || println!("Hello, world!"); call(hello); call(hello); // Many `Iterator` combinators are now `Copy`/`Clone`: let x = (1..100).map(|x| x * 5); let _ = x.map(|x| x - 3); // moves `x` by `Copy`ing let _ = x.chain(y); // moves `x` again let _ = x.cycle(); // `.cycle()` is only possible when `Self: Clone` // Closures which reference data mutably are not `Copy`/`Clone`: let mut x = 0; let incr_x = || x += 1; call(incr_x); call(incr_x); // ERROR: `incr_x` moved in the call above. // `move` closures implement `Clone`/`Copy` if the values they capture // implement `Clone`/`Copy`: let mut x = 0; let print_incr = move || { println!("{}", x); x += 1; }; fn call_three_times<F: FnMut()>(mut f: F) { for i in 0..3 { f(); } } call_three_times(print_incr); // prints "0", "1", "2" call_three_times(print_incr); // prints "0", "1", "2" }

Motivation

Idiomatic Rust often includes liberal use of closures. Many APIs have combinator functions which wrap closures to provide additional

追加の
functionality (e.g. methods in the Iterator and Future traits).

However, closures are unique,

一意
unnameable types which do not implement
実装する
Copy or Clone. This makes using closures unergonomic and limits their usability. Functions which take
とる
closures, Iterator or Future combinators, or other closure-based types by-value are impossible to call
呼び出し
multiple
複数の
times.

One current workaround is to use the coercion from non-capturing closures to fn pointers, but this introduces unnecessary dynamic

動的
dispatch and prevents
防ぐ
closures from capturing values, even zero-sized ones.

This RFC solves this issue by implementing

実装する
the Copy and Clone traits on closures where possible.

Guide-level explanation

If a non-move closure doesn't mutate captured variables,

変数、ストレージ
then it is Copy and Clone:

#![allow(unused)] fn main() { let x = 5; let print_x = || println!("{}", x); // `print_x` is `Copy + Clone`. // No-op helper function which moves a value fn move_it<T>(_: T) {} // Because `print_x` is `Copy`, we can pass it by-value multiple times: move_it(print_x); move_it(print_x); }

Non-move closures which mutate captured variables

変数、ストレージ
are neither Copy nor Clone:

#![allow(unused)] fn main() { let mut x = 0; // `incr` mutates `x` and isn't a `move` closure, // so it's neither `Copy` nor `Clone` let incr = || { x += 1; }; move_it(incr); move_it(incr); // ERROR: `print_incr` moved in the call above }

move closures are only Copy or Clone if the values they capture are Copy or Clone:

#![allow(unused)] fn main() { let x = 5; // `x` is `Copy + Clone`, so `print_x` is `Copy + Clone`: let print_x = move || println!("{}", x); let foo = String::from("foo"); // `foo` is `Clone` but not `Copy`, so `print_foo` is `Clone` but not `Copy`: let print_foo = move || println!("{}", foo); // Even closures which mutate variables are `Clone + Copy` // if their captures are `Clone + Copy`: let mut x = 0; // `x` is `Clone + Copy`, so `print_incr` is `Clone + Copy`: let print_incr = move || { println!("{}", x); x += 1; }; move_it(print_incr); move_it(print_incr); move_it(print_incr); }

Reference-level explanation

Closures are internally represented

表現する
as structs
構造、構造体
which contain
含む
either values or references
参照
to the values of captured variables
変数、ストレージ
(move or non-move closures). A closure type implements
実装する
Clone or Copy if and only if the all values in the closure's internal representation
表現
implement
実装する
Clone or Copy:

  • Non-mutating non-move closures only contain

    含む
    immutable
    不変の
    references
    参照
    (which are Copy + Clone), so these closures are Copy + Clone.

  • Mutating non-move closures contain

    含む
    mutable references,
    参照
    which are neither Copy nor Clone, so these closures are neither Copy nor Clone.

  • move closures contain

    含む
    values moved out of the enclosing
    囲う
    scope, so these closures are Clone or Copy if and only if all of the values they capture are Clone or Copy.

The internal implementation

実装
of Clone for non-Copy closures will resemble the basic implementation
実装
generated
生成する
by derive, but the order
順序
in which values are Cloned will remain unspecified.
特定されていない

Drawbacks

This feature increases

増加する、昇順の
the complexity of the language,
言語
as it will force users to reason about which variables
変数、ストレージ
are being captured in order
順序
to understand whether or not a closure is Copy or Clone.

However, this can be mitigated through error messages which point to the specific

特定の
captured variables
変数、ストレージ
that prevent
防ぐ
a closure from satisfying
満たす、満足させる
Copy or Clone bounds.
制限する、結び付けられて

Rationale and Alternatives

It would be possible to implement

実装する
Clone or Copy for a more minimal set
セットする、集合
of closures, such as only non-move closures, or non-mutating closures. This could make it easier to reason about exactly
正確に
which closures implement
実装する
Copy or Clone, but this would come at the cost of greatly decreased functionality.

Unresolved questions

  • How can we provide high-quality, tailored error messages to indicate
    指し示す
    why a closure isn't Copy or Clone?