How to return: BufReader

Hi,

I have problem understanding why I cannot return my reader form a function. Example:

use std::io::{prelude::*, Read,  BufReader};
use std::fs::File;


fn get_reader<R: Read>(file:&str)-> BufReader<R>{

    let mut fin;
    let read: &mut dyn Read = match file {
        _       => {
            fin = File::open(file).expect(&(format!("Error opening {} file",file)));
            &mut fin
        }
    };

    let mut reader = BufReader::new(read);

    reader
}

fn main() {

   let mut r = get_reader("log.txt");

  for l in r.lines(){
    //blah
  }
}

the example is truncated to simplify a real scenario which has several matching conditions.

thank you !

read has type &mut dyn Read, so BufReader::new(read) has type BufReader<&mut dyn Read>, not BufReader<R>.

Furthermore, by returning something that wraps the pointer to fin, you'd be trying to return the address of a local variable anyway, which is an error. I'm wondering why you don't just return BufReader<File> by wrapping the file object into the BufReader directly (by value)? It doesn't seem you need the generic type parameter R at all. I.e.:

fn get_reader(file: &str) -> BufReader<File> {
    BufReader::new(File::open(file).expect(&format!("Error opening {} file", file))
}

It also looks like you're not clear on what the difference between generics and dyn Trait is, and/or why one wants to use generics in general. I'd suggest reading up more on that.

2 Likes

well when I fix it i get cannot return value referencing local variable 'fin' And Yes I am not sure ... Still learning and therefore when you or someone else here gives me pointers (like you did) I know where to look, it help enormously ... Thank you !

That's exactly what I was pointing out in the second paragraph. It should work if you just write the example I gave.

Update: Maybe i framed it incorrectly and did not read your post thoroughly ... just a sec before reading further ...

And it does but what if I wanna return a Read from stdin but I do not know what I want to do at compile time:

    let mut stdin;
    let mut fin;
    let read: &mut dyn Read = match file {
        "stdin" => {
            stdin = io::stdin();
            &mut stdin
        },
        _       => {
            fin = File::open(file).expect(&(format!("Error opening {} file",file)));
            &mut fin
        },
        "I have several other 'dubious' conditions here" => {}

    };
    let reader = BufReader::new(read);

   reader

how to deal with it then ?

Then you do need a trait object, indeed. However, you still want to return by-value, which you can achieve using Box<dyn Read>, and in turn BufRead<Box<dyn Read>>, e.g.:

let read: Box<dyn Read> = match file {
    "stdin" => Box::new(io::stdin()),
    _ => Box::new(File::open(file).expect("…")),
};

BufReader::new(read)
1 Like

It worked !... Sorry for wasting your time ... I framed the question inadequately and wasted 1h ...

so if anyone else needs it :

fn get_reader (file: &str) -> BufReader<Box< dyn Read >>{
    let reader = match file {
        "stdin" => {
            let mm : Box<dyn Read> = Box::new(io::stdin());
            BufReader::new(mm)
        },
        _       => {
            let mm : Box<dyn Read> = Box::new(File::open(file)
                .expect(&(format!("Error opening {} file",file))));
            BufReader::new(mm)
        }
    };
    reader
}

H2CO3: I would not repeat the creation of the BufReader , though, it can be created just once, outside the match .

pub fn get_reader(file: &str)-> BufReader<Box< dyn Read >> {

    let read : Box<dyn Read> = match file {
        "stdin" => {
            Box::new(io::stdin())
        },
        _       => {
            Box::new(File::open(file)
                .expect(&(format!("Error opening {} file",file))))
        }
    };
    BufReader::new(read)
}

I would not repeat the creation of the BufReader, though, it can be created just once, outside the match.

1 Like

A tangential note: there is a "standard" convention followed in unix command line tools to use a dash (-) to mean stdin/stdout.

Depending on what you're doing, you may want to follow that convention.

2 Likes