Hi, I'm studying closures. Would you say this writeup is about correct? My test code.
if (you "carelessly" "destroy" any of the variables on parent stack by moving content out of them) {
you get FnOnce
those variables are moved to the closure on creation
if (you also use "move" keyword) {
all accessed variables from the parent frame not mentioned above which are not "Copy" are also moved to the closure
all accessed variables from the parent frame not mentioned above which are "Copy" are copied to the closure
} else {
all accessed variables from the parent frame not mentioned above are referenced by the closure via & and &mut
}
} else {
if (use "move" keyword) {
all accessed variables from the parent frame which are not "Copy" are moved to the closure
and accessed variables from the parent frame which are "Copy" are copied to the closure
} else {
all accessed variables from the parent frame are referenced by the closure via & and &mut
}
if (you modify any variables on/from parent stack frame) {
you get FnMut
} else {
you get Fn
}
}
I think you're correct, but I believe the trait vs. capture "style" can be a little more independent than how you've written it:
// trait:
if (some non-Copy variable is used by value) {
FnOnce
} else if (some variable is modified (i.e. used by &mut reference)) {
FnMut
} else { // all variables are used by & reference
Fn
}
// capture "style":
for variable in parent_variables {
if ("move" keyword on closure) || (`variable` is used by value) {
`variable` is captured by value
} else (`variable` is used by `&mut` reference) {
`variable` is captured by `&mut` reference
} else { // only used by & reference
`variable` is captured by `&` reference
}
}
The loop could also be written as:
if ("move" keyword) {
all variables are captured by value
} else {
each variable is captured by value, by &mut reference or by & reference, matching how it is used
}
NB. I've mostly folded non-Copy and Copy types together, by just talking about being used by value or by reference. A Copy-copy and a move are essentially the same thing, both occur when using something by-value, e.g. foo(a) or b = a are both using a by value. The only difference is the source (a) can continue to be used after that for Copy types, and the same applies to closure-captures.
Incidentally, I've done some writing on both closures and moves/copies, which others have apparently found helpful, so you may be interested too:
Oh, whoops. I realised that after writing, and corrected the trait inference (FnOnce only applies for non-Copy variables), to be clear it should read ("move" keyword on closure) || (`variable` is not `Copy` and used by value).
The reason is Copy types can be copied out to be by-value from behind &T references, i.e. let _ = a; is the same as let _ = *(&a);: a use by-&-reference.