Help with generic types in structs

Why does the following code not compile?

    use std::fs::File;
    use std::io::{BufReader, Read};
    use std::path::PathBuf;
    
    pub struct BufReaderStruct<R: Read> {
        pub reader: Option<BufReader<R>>,
    }

    impl <R: Read> BufReaderStruct<R> {
        pub fn new(reader: R) -> Self {
            BufReaderStruct {
                reader: Some(BufReader::new(reader)),
            }
        }

        pub fn new_from_file(path: &PathBuf) -> Self {
            let file = File::create(path).unwrap();
            BufReaderStruct::new(file)
        }
    }

    fn main() {
        let file = File::create("tmp.txt").unwrap();
        let _a = BufReaderStruct::new(file);
        let _b: BufReaderStruct<File> = BufReaderStruct::new_from_file(&PathBuf::from("tmp.txt"));
        let _c = BufReaderStruct::new("Hello World".to_owned().as_bytes());
    }

but the following example compiles:

    use std::fs::File;
    use std::io::{BufReader, Read};
    use std::path::PathBuf;
    
    pub struct BufReaderStruct<R: Read> {
        pub reader: Option<BufReader<R>>,
    }

    impl <R: Read> BufReaderStruct<R> {
        pub fn new(reader: R) -> Self {
            BufReaderStruct {
                reader: Some(BufReader::new(reader)),
            }
        }
    }

    pub fn new_from_file(path: &PathBuf) -> BufReaderStruct<File> {
        let file = File::create(path).unwrap();
        BufReaderStruct::new(file)
    }

    fn main() {
        let file = File::create("tmp.txt").unwrap();
        let _a = BufReaderStruct::new(file);
        let _b: BufReaderStruct<File> = new_from_file(&PathBuf::from("tmp.txt"));
        let _c = BufReaderStruct::new("Hello World".to_owned().as_bytes());
    }

Your new_from_file method is defined such that given a path, it can produce a BufReaderStruct<R> for any choice of type R that implements the Read trait, but this is not true. It can only produce an BufReaderStruct<File>, not e.g. a BufReaderStruct<TcpStream>.

You can split the impl block like this:

impl<R: Read> BufReaderStruct<R> {
    pub fn new(reader: R) -> Self {
        BufReaderStruct {
            reader: Some(BufReader::new(reader)),
        }
    }
}

impl BufReaderStruct<File> {
    pub fn new_from_file(path: &PathBuf) -> Self {
        let file = File::create(path).unwrap();
        BufReaderStruct::new(file)
    }
}
1 Like