The best practice to solve error[E0502]


#1

I am a newbie in Rust, and I am trying to learn it step by step. I would know what is the best practice to solve the E0502 in the following example:

let mut numbers_str = String::new(); 

io::stdin().read_line(&mut numbers_str).ok().expect("read error");
//let numbers_str_c = numbers_str.clone(); // 1st solution
let numbers1 = { numbers_str.split_whitespace() // immutable borrow occurs here
    .map(|s| s.parse::<i32>().unwrap())
};

//let mut numbers_str2 = String::new(); // 2nd solution
io::stdin().read_line(&mut numbers_str).ok().expect("read error"); // mutable borrow occurs here
let numbers2 = numbers_str.split_whitespace()
    .map(|s| s.parse().unwrap());

let i = numbers1.zip(numbers2).fold(blablabla);

And I want to meet the following constraints:

  1. I want to read a line from stdin twice using same name of variable numbers_str as a buffer because I want to copy&paste same code twice.
  2. I understand that I should free a memory before second use of numbers_str but I didn’t find a method to do that.
  3. I don’t want to use 1st and 2nd solutions mentioned in comments, it doesn’t look elegant
  4. I don’t want to make a function to read and parse a line because I want to write this code as fast as possible in the future.
    Is it possible?
    I read other related topics but didn’t find a solution or they[topics] were very complex for me.

#2

Just to make sure you understand the reason for the error – numbers1 is an iterator, that will lazily parse the numbers from the numbers_str string (the actual parsing will occur on the call to fold) – that’s why it borrows numbers_str.

So there are basically two solutions – either don’t touch the numbers_str until fold, or parse these numbers eagerly, eg. storing in the Vec:

let numbers1: Vec<_> = numbers_str.split_whitespace()
    .map(|s| s.parse::<i32>().unwrap())
    .collect();
// the numbers_str is no longer borrowed
numbers_str.clear();

Speaking of your 2nd solution from comment, if you find it ugly because you have to use a variable with different name, don’t worry. You can call it numbers_str too. Creating new variable with the same name doesn’t destroy the old one (it won’t be directly accessible, but it’s still there from the perspective of borrows).


#3

Creating new var with the same name is a suitable solution. I am worrying about memory consumption only, it will allocate additional memory despite on the fact that second line has same size as first line.

I put numbers_str.split_whitespace() after the fold call and I got same e0502.


#4

(emphasis mine) It seems that you’re suggesting here that second line could somehow reuse the memory allocated to store the first line. It’s definitely possible – if you go with the solution of collect + clear that I’ve described. If you don’t collect the numbers, you basically require two line-strings to be allocated at the same time – that’s just the requirement of your current approach.

If I understand correctly what you’ve done (playground) the error is a limitation of a current lifetime system – as long as numbers1 variable exists, the numbers_str will be considered borrowed, no matter if the numbers1 have been moved out from or not. The current workaround is to limit the lifetime of variable with braces: playground

Anyway, how long are these lines that you worry about the memory consumption? If they are really long you can consider only storing the first line and processing the second line in a streaming way (no niceties like read_line or split_whitespace here though, you’d have to do it manually). If the data is stored in a file, you can even open the file twice and process both lines in a streaming way.


#5

It seems now you can sure. :slight_smile: Thank you!