Hacker News new | past | comments | ask | show | jobs | submit login

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();
No capture list needed, same control.



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.


How would you do the equivalent of this in Rust?

  auto on_heap = std::make_unique<MyType>(...);

  function_that_accepts_lambda([obj = std::move(on_heap)]() {
     obj->bar(...);
  })


    let on_heap = Box::new(...);

    function_that_accepts_lambda(move || {
        on_heap.bar();
    });
This is sort of what kibwen was mentioning: move is a single annotation that overrides everything to capture by value rather than have it inferred.


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(....);


I am 99% sure this is identical:

    let on_heap = Box::new(...);
    let shared = Arc::new(...);

    let s = shared.clone();
    function_that_accepts_lambda(move || {
        on_heap.bar();
        s.foo();
    });
We have to make the extra s binding.

Also, my sibling is correct that Copy types will just be copied, not moved.


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.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: