Is there a better way to read in a labeled data file?

I need my programs to be able to read in a labeled input file, perform calculations, and save it to an output file. I wrote a basic program that calculates the hypotenuse of a right triangle by taking in the other sides with the following input file.

input.txt:

a, 3.0
b, 4.0

This is my current solution which outputs a number to a text file in the Outputs folder:

use std::fs::File;
use std::fs;
use std::io::{self, BufRead};
use std::path::Path;

fn main() {
    // Creating an array to save the file inputs
    let mut data_array: [f32; 2] = [0.0;2];

    // reading the file inputs
    if let Ok(lines) = read_lines("Inputs/input.txt") {
        let mut i = 0;
        for line in lines {
            if let Ok(ip) = line {
                let split = ip.split(", ");
                let vec: Vec<&str> = split.collect();
                data_array[i] = vec[1].trim().parse().expect("Check Number");
                i = i + 1;
            }
        }
    }
    
    // Saving the numbers to variables
    let a: f32 = data_array[0];
    let b: f32 = data_array[1];
    
    // Writing out hypotenuse to file
    fs::write("Outputs/output.txt", ((a*a) + (b*b)).sqrt().to_string())
        .expect("Unable to write to file");
}

// The recommended way to read in by lines from the Rust Cookbook
// https://doc.rust-lang.org/rust-by-example/std_misc/file/read_lines.html
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where P: AsRef<Path>, {
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}

My current solution feels slightly obtuse but does get the job done. Is there a better way to accomplish this task?

Here's a vastly simplified version.

The most important modifications were:

  • Don't use array indexing for iteration. Use iterators.
  • Don't use array indexing for destructuring entire fixed-size arrays. Use pattern matching.
  • Handle errors instead of panicking on them or worse yet, ignoring them. Instead of deeply nested trees of if-let, use the ? operator.
  • Don't convert the result to string, that's an unnecessary allocation. If you need to write out formatted data, use the write!() family of macros, which take a format string and write directly to the file without any intermediate strings.
  • Don't compute the hypotenuse by hand, it's not as trivial as you might think. f32::hypot() is a numerically stable implementation that ensures good-quality results even in edge cases related to very small and very large floating-point numbers.
3 Likes

Thank you very much @H2CO3 ! Your explanation and code sample are extremely helpful! I'm still getting used to how Rust is structured as opposed to Fortran90.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.