How to iterate and extract values out of a for loo

2019-02-22 10:51发布

问题:

I'm new to Rust and looking to understand concepts like borrowing. I'm trying to create a simple two dimensional array using standard input. The code:

use std::io;

fn main() {
    let mut values = [["0"; 6]; 6]; // 6 * 6 array

    // iterate 6 times for user input
    for i in 0..6 {
        let mut outputs = String::new();
        io::stdin().read_line(&mut outputs).expect(
            "failed to read line",
        );

        // read space separated list 6 numbers. Eg: 5 7 8 4 3 9
        let values_itr = outputs.trim().split(' ');
        let mut j = 0;
        for (_, value) in values_itr.enumerate() {
            values[i][j] = value;
            j += 1;
        }
    }
}

This won't compile because the outputs variable lifetime is not long enough:

error[E0597]: `outputs` does not live long enough
  --> src/main.rs:20:5
   |
14 |         let values_itr = outputs.trim().split(' ');
   |                          ------- borrow occurs here
...
20 |     }
   |     ^ `outputs` dropped here while still borrowed
21 | }
   | - borrowed value needs to live until here

How can I get the iterated values out of the block into values array?

回答1:

split() gives you substrings (string slices) borrowed from the original string, and the original string is outputs from line 6.

  1. The string slices can't outlive the scope of outputs: when a loop iteration ends, outputs is deallocated. Since values is longer lived, the slices can't be stored there.
  2. We can't borrow slices of outputs across a modification of outputs. So even if the String outputs itself was defined before values, we couldn't easily put the string slices from .split() into values; modifying the string (reading into it) invalidates the slices.

A solution needs to either

  • Use a nested array of String, and when you assign an element from the split iterator, make a String from the &str using .to_string(). I would recommend this solution. (However an array of String is not at as easy to work with, maybe already this requires using Vec instead.) 1
  • Read all input before constructing a nested array of &str that borrows from the input String. This is good if the nested array is something that you only need temporarily.

1: You can use something like vec![vec![String::new(); 6]; 6] instead



回答2:

This answer was moved from the question, where it solved the OPs needs.

use std::io;

fn main() {
    let mut values = vec![vec![String::new(); 6]; 6];
    for i in 0..6 {
        let mut outputs = String::new();
        io::stdin().read_line(&mut outputs)
                .expect("failed to read line");

        let values_itr = outputs.trim().split(' ');
        let mut j = 0;
        for (_, value) in values_itr.enumerate() {
            values[i][j] = value.to_string();
            j += 1;
        }
    }
}


标签: for-loop rust