Search code examples
rustreferenceborrow-checker

Confused about creating longer lived reference to String


I'm trying to improve my Rust skills and running into confusion about getting references and lifetimes working how I want. I am trying to read lines from a string and 'rotate' the last two through a couple variables.

This works:

fn main() {
    let test_lines = "line 1
        line 2
        line 3
        line 4
        line 5";
    let mut lines = test_lines.lines();

    let mut a = &String::new();
    let mut b = &String::new();
    println!("{} - {}", a, b);

    let temp = lines.next().unwrap().trim().to_string();
    a = b;
    b = &temp;
    println!("{} - {}", a, b);

    let temp = lines.next().unwrap().trim().to_string();
    a = b;
    b = &temp;
    println!("{} - {}", a, b);

    let temp = lines.next().unwrap().trim().to_string();
    a = b;
    b = &temp;
    println!("{} - {}", a, b);
}

and produces:

 - 
 - line 1
line 1 - line 2
line 2 - line 3

But when I try to roll it up in a loop:

fn main() {
    let test_lines = "line 1
            line 2
            line 3
            line 4
            line 5";

    let mut a = &String::new();
    let mut b = &String::new();

    let temp;
    for line in test_lines.lines() {
        a = b;
        temp = line.trim().to_string();
        b = &temp;

        println!("{} - {}", a, b);
    }
}

I get this error:

error[E0506]: cannot assign to `temp` because it is borrowed
  --> src/main.rs:68:9
   |
68 |         temp = line.trim().to_string();
   |         ^^^^ `temp` is assigned to here but it was already borrowed
69 |         b = &temp;
   |             ----- `temp` is borrowed here
70 |
71 |         println!("{} - {}", a, b);
   |                             - borrow later used here

I've read over the explain for the error, but I don't see the borrow. (And I swear I saw this work once...)

I'm trying to create String objects for each line of the input and keep a couple pointers to the last two lines (for use in other processing). I expect that the 'older' lines will be dropped when a and b are re-assigned.

I can see quite clearly how to do this in C or C++, but not understanding how to get Rust to do this.


Solution

  • There is no advantage if the type of b is &String instead of String.

    fn main() {
        let test_lines = "line 1
                line 2
                line 3
                line 4
                line 5";
        let mut a;
        let mut b = String::new();
        let mut temp;
    
        for line in test_lines.lines() {
            a = b;
            temp = line.trim().to_string();  // could be assigned directly to b
            b = temp;
    
            println!("{a} - {b}");
        }
    }
    

    Playground