Rust code that reads two columns of data from .txt file I'm writing a code to read data from text file in Rust. The target files have two columns and non-fixed length rows, for example,

example.txt

1  1
2  4
3  9
4  16


To achieve this, I wrote following code.

use std::fs::read_to_string;

pub fn open_file(filename: &amp;str) -&gt; (Vec&lt;f32&gt;, Vec&lt;f32&gt;){
    let data = read_to_string(filename);
    let xy = match data {
        Ok(content) =&gt; content,
        Err(error) =&gt; {panic!("Could not open or find file: {}", error);}
    };

    let xy_pairs: Vec&lt;&amp;str&gt; = xy.trim().split("\n").collect();
    let mut x: Vec&lt;f32&gt; = Vec::new();
    let mut y: Vec&lt;f32&gt; = Vec::new();

    for pair in xy_pairs {
        let p: Vec&lt;&amp;str&gt; = pair.trim().split(" ").collect();

        x.push(p[0].parse().unwrap());
        y.push(p[1].parse().unwrap());
    }

    (x, y)
}


I'm a beginner of Rust, so I don't know that I follow the best practice in Rust and this is the most efficient code.

I want some advice about this function.
I honestly think you should be breaking up the treatment of the file into two parts, as you are already (implicitly) doing so in your function. One part to read the file into a line iterator, another to actually parse.

The "reading into an iterator" is a simple combination of std::fs::File::read_line; I'll instead focus on the other part:

pub fn read_xy_pairs(i: impl Iterator&lt;Item = String&gt;) -&gt; (Vec&lt;f32&gt;, Vec&lt;f32&gt;) {
    i
        .map(|string| -&gt; Vec&lt;f32&gt; {
            string.split(" ")
                .take(2)
                .map(|element| element.parse::&lt;f32&gt;())
                .filter(|element| element.is_ok())
                .map(|element| element.unwrap())
                .collect()
        })
        .filter(|item| item.len() == 2)
        .map(|mut item| (item.swap_remove(0), item.swap_remove(0)))
        .unzip()
}


The processing is clearly laid out, in order:


I convert each element of the iterator, in turn, into an iterator of &amp;str via String::split()
I then truncate this iterator to only take the first two elements lazily
Each element of this iterator gets parsed() and I filter any element that isn't okay, unwrapping those that are
This iterator gets collected into a Vec&lt;f32&gt;
From there, I filter out any element that does not have exactly 2 components, and convert those that do into a tuple2 of (f32, f32)
I then unzip this iterator of (f32, f32) into a (Vec&lt;f32&gt;, Vec&lt;f32&gt;) to fit your type signature