3

new to rust, I'm asking this to hopefully understand how to work with the language better..

Heres me trying to read a file, pass the file handle to a different function and print the lines from there:

use std::fs::File;
use std::io::{self, BufReader};
use std::io::BufRead;
use async_std::task;

async fn scrape<R: BufRead>(reader: &mut R) {
    reader.lines().for_each(|line| println!(line));
}

fn main() -> io::Result<()> {
    let file = File::open("wlist.txt")?;
    let reader = BufReader::new(file);

    // print_type_of(&reader); // prints std::io::buffered::BufReader<std::fs::File>
    task::block_on(scrape(&mut reader));

    Ok(())
}

// helper functions
fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}

Would love some insights regarding what concepts i'm missing and how this should be done properly !

toti
  • 325
  • 4
  • 12
  • you can `scrape(&mut reader).await` this async task – Alexey S. Larionov May 30 '20 at 17:21
  • It's also frequently easier for optimizer to speed up an iterator consumption in comparison to `for` loops, so you better avoid loops unless it greatly eases your code. You can `reader.lines().for_each(|line| println!(line));` – Alexey S. Larionov May 30 '20 at 17:25
  • also `reader.lines()` returns an iterator over `io::Result`, not just strings. So you have to catch IO errors in your function – Alexey S. Larionov May 30 '20 at 17:29
  • thank you for the tips! still waiting for more help with this since i can't get it to work – toti May 30 '20 at 17:44
  • What's the problem? The error I get is ``error: format argument must be a string literal`` which doesn't seem to have anything to do with `async` or `BufReader`. – trent May 30 '20 at 18:05
  • [I found this question by searching for the error message.](https://stackoverflow.com/questions/27734708/println-error-expected-a-literal-format-argument-must-be-a-string-literal) – trent May 30 '20 at 18:07

1 Answers1

3

This version atleast compiles, but there's no async in the playground so I coudn't add async.

You have to catch errors in scrape by using try_for_each function, inside you parse io::Result<String> via and_then. In your main you have to catch all errors explicitly, not allowed to let io::Error slip through ? operator

use std::fs::File;
use std::io::{self, BufReader};
use std::io::BufRead;
//use async_std::task;

fn scrape<R: BufRead>(reader: &mut R) -> io::Result<()> {
    reader.lines()
        .try_for_each(|lineResult| lineResult.and_then(|line| Ok(println!("{}", line))))?;
    Ok(())
}

fn main() {
    //let fileResult = File::open("wlist.txt");
    //let mut file;
    //match fileResult {
    //    Ok(f) => file = f,
    //    Err(e) => println!("File open error! {}", e),
    //}
    let mut file = b"hello\nworld\nhow\nare\nyou\ndoing" as &[u8]; // no file in playground, so just a buffer
    let mut reader = BufReader::new(file);

    // print_type_of(&reader); // prints std::io::buffered::BufReader<std::fs::File>
    match scrape(&mut reader) {
        Ok(_) => println!("Scraping is done!"),
        Err(e) => println!("File read error! {}", e),
    }
}

// helper functions
fn print_type_of<T>(_: &T) {
    println!("{}", std::any::type_name::<T>())
}
Alexey S. Larionov
  • 6,555
  • 1
  • 18
  • 37
  • This is super informative and helpful, currently messing around with the code and already learning so THANKS. only error left is when I use your uncommented version of the file from text file instead of binary - it errors on the `BufReader::new(file);` line with this `error: use of possibly-uninitialized file` – toti May 30 '20 at 18:44
  • You can change to `Err(e) => { println!("File open error! {}", e); return; },` in first `match` – Alexey S. Larionov May 30 '20 at 19:02