> Whereas in the functional world, you’ll have to 4 different ‘.read’ function calls with an if statement.
A good language for functional programming provides parametric polymorphism via traits or typeclasses:
pub trait Read {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>;
}
impl Read for std::fs::File { /* ... */ }
impl Read for String { /* ... */ }
Then you can write a generic function like this: pub fn read_kilobyte<R>(r: R) -> io::Result<Vec<u8>>
where R: std::io::Read {
let mut buf = vec![0u8; 1024]; // vector of 1024 0s
let nbytes = r.read(&mut buf[..])?;
buf.truncate(nbytes);
Ok(buf)
}
And call it like this: let kb1 = read_kilobyte(File::open(...)?)?;
let kb2 = read_kilobyte("foo bar baz quux".to_string())?;
No ifs in sight.