It's a trade off more than a necessity. For example, Rust doesn't have explicit capture lists, and if you want explicit control, you make new bindings and capture those. You almost never need to do this in Rust, so it's optimized for that case; I haven't written many closures in C++, so I can't say as much about the frequency there.
To make this more concrete:
let s = String::from("s");
let closure = || {
println!("s is: {}", s);
};
closure();
If you wanted to capture s in a different way:
let s = String::from("s");
let s1 = &s;
let closure = || {
println!("s1 is: {}", s1);
};
closure();
Rust doesn't have explicit capture lists, but it does have the `move` modifier on closures which is like C++'s `[=]`.
Strictly speaking, Rust probably could have gotten away with having neither the `move` modifier nor capture clauses at all, but it would have had wide-ranging implications on the ergonomics and capabilty of closures.
What if you want to move some things, but copy others?
e.g.
auto shared = std::make_shared<MySharedType>(...);
auto unique = std::make_unique<MyOwnedType>(...);
function_that_accepts_lambda([shared, u = std::move(unique)] {
shared->foo(...); u->bar(...);
});
// Outer scope can still use shared.
shared->foo(....);
If the type implements Copy they'll be implicitly copied when moved into the Rust closure(I think). Or you can declare a scope var and clone() manually.
To make this more concrete:
If you wanted to capture s in a different way: No capture list needed, same control.