Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid borrowing a value that was moved into a closure without using clone?

Tags:

rust

I'm trying to understand the closures in Rust. I wrote a code like this;

use std::ops::Add;

fn main() {
    let mut a = "a string".to_string();

    let mut cl = ||  {
        a.add(" another string");
    };

    cl();

    println!("{:?}", a);
}

I expect a result like "a string another string". In the documentation it says that try to avoid using clone() where possible, but I can't manage to compile this code without using a = a.clone().add(" another string").

like image 526
Onur Eren Elibol Avatar asked Nov 28 '25 02:11

Onur Eren Elibol


2 Answers

To answer your original question: You can't. This is because your string a is moved into the closure. You can't have it back though. See Denys answer for a solution.


A solution to this specific problem would be to use push_str instead of Add, because push_str requires a mutable referece instead of a moved value.

fn main() {
    let mut a = "a string".to_string();

    let mut cl = || {
        a.push_str(" another string");
    };

    cl();

    println!("{:?}", a);
}
like image 151
hellow Avatar answered Nov 29 '25 16:11

hellow


A solution would be to move the value to the closure, then make it return it:

use std::ops::Add;

fn main() {
    let mut a = "a string".to_string();
    let cl = ||  {
        a.add(" another string")
    };
    a = cl();
    println!("{:?}", a);
}

But capturing the outer scope is rather limited. You can't for example have two closures defined this way. You might want a more flexible solution:

let a = "a string".to_string();
let c1 = |s: String|  {
    s.add(" another string")
};
let c2 = |s: String|  {
    s + " and another one"
};
let a = c1(a);
let a = c2(a);
like image 42
Denys Séguret Avatar answered Nov 29 '25 14:11

Denys Séguret