let file = File::open(path).expect("the path to reader does not exist");
let mut dec = FrameDecoder::new(file);
let mut buf = Vec::<u8>::new();
std::io::copy(&mut dec, &mut buf).expect("decode failed"); // works
dec.read_to_end(&mut buf).unwrap(); // method not found in `snap::read::FrameDecoder<std::fs::File>`
I thought because the source code of FrameDecoder have use std::io::Read, so I would get use std::io::Read for free, without importing it. Is it not how Rust works?
No, you need to import the trait that defines a method if you wish to use that method. This is because there might be multiple traits that define a read_to_end method, and this allows the compiler to tell which one to use.
E.g. otherwise you risk the situation where you later add a dependency containing this, and having your code stopping to compile, because now there are suddenly two read_to_end methods on FrameDecoder.
// in some third party crate
trait MyTrait {
fn read_to_end(&mut self, buf: &mut String) -> io::Result<usize>;
}
impl MyTrait for FrameDecoder {
fn read_to_end(&mut self, buf: &mut String) -> io::Result<usize> { todo!() }
}
Some crates actually use this technique to add methods to existing types. An example of this is itertools, which adds methods to all iterators. You can only use these methods if you import the extension trait.