loopsrustborrowing

Trying to borrow variable binding from outside of loop in Rust


    // I want to use this...
    let group = svg::node::element::Group::new();

    for (index, character) in label_string.char_indices() {

        let character = svg::node::Text::new(character);

        let text = svg::node::element::Text::new()
        .set("x", 0 + 16 * index)
        .set("y", 20)
        .set("font-family", "Hack")
        .set("font-size", 16)
        .set("fill", color::color(foreground_color))
        .add(character);

        // ...inside this for loop.
        group.add(text);

    }

But I am told use of moved value: group because value moved here, in previous iteration of loop.

Which makes sense. But I can't figure out how to just borrow group instead. The for syntax doesn't give me any way do this, and these haven't work either:

    for (index, character) in label_string.char_indices() {
        ...
        let group_ref = &group;
        group_ref.add(text);
    }
    let group_ref = &group;
    for (index, character) in label_string.char_indices() {
        ...
        group_ref.add(text);
    }

Note: Trying to borrow variable binding from outside of loop doesn't answer this question.


Solution

  • svg::node::element::Group::add has the following signature:

    impl Group {
        pub fn add<T>(self, node: T) -> Self
        where
            T: Node,
        { /* ... */ }
    }
    

    From this signature we can see that the method takes self by value (not by reference, like &self or &mut self), which means that when you call group.add(text) from within your loop, you move the value out of the group variable (since the add method needs to take ownership). By the next time iteration of the loop, there is no value in the variable, so the compiler will complain.

    However, we can also see that the method returns Self, which indicates that we get a new value that we can just re-assign to group. That way, by the end of the iteration (and beginning of the next) we will have a value in the group variable that has not been moved out:

    // note that we need this to be mut now, since we're reassigning within the loop
    let mut group = svg::node::element::Group::new();
    
    for (index, character) in label_string.char_indices() {
        // ...
    
        // since `group.add()` takes ownership of `group`, but returns a new value,
        // we can just reassign to `group`, so that it is present for the next iteration
        group = group.add(text);
    
    }