file.read_to_end(&mut bytes)?;
`bytes` is already mutable. `read_to_end` is already declared as taking a `&mut Vec<u8>`. So why force every caller to do a `&mut` un-necessarily ?By being explicit about this, Rust becomes easier to read, but (slightly) harder to write.
Because it's not unnecessary? `bytes` is a `Vec`, not a `&mut Vec`, those are different things, and Rust generally avoids magically doing things under the covers. So it doesn't auto-ref (let alone auto-mut-ref) parameters, only subjects.
fun read(path: &Path): io.Result[Vec[UInt8] {
var file = File.open(path).orReturnErr()
var bytes = Vec.new()
file.readToEnd(&mut bytes).orReturnErr()
Ok(bytes)
}
would be good enough for me, tbh.Method syntax is reserved for functions. There are no method syntax macros. Since a return in a function terminates execution of this function, and not its caller, your example would not work.
let a: Result<u8, u8> = /* whatever *;
let b = match a {
Ok(v) => Ok(foo(v)),
e => e,
};
and transform it into: let a: Result<u8, u8> = /* whatever *;
let b = a.map(foo);
if "foo" is a macro. When you substitute "foo!" for all the "foo" above, it is obvious.await cannot be a macro, it has to be built into the language, and so it doesn't have the ! because it's not one.
"orReturnErr()" seems quite against the Rust philosophy though — refusing the method call syntax for early return means folks can easily miss something important. Rust uses ? for error handling, ! for macros, and keywords (with no parenthesis) for other control flow. I prefer it that way.
(defn Read [path]
(io/ReadToEnd (os/Open path)))
Now that's what I call readable! File::open(path)?.read_to_end()
but instead read_to_end is written to take a presupplied Vec so the caller has the option to reduce allocations.Unsurprisingly APIs can be more readable when you don't ponder why they're designed the way they are and completely ignore their purpose.
The `read_to_end` API[0] was designed such that the buffer could be reused in order to avoid unnecessary allocations.
There are helpers for common tasks, though people may not know or notice them. In the case of `Read::read_to_end`, it's called std::fs::read[1], which actually preallocates the vector based on file size internally so might be faster than hand-rolling `read_to_end`.
So here's your code in Rust, for the last 3 years or so (since 1.26 was released):
fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
std::fs::read(path)
}
[0] and all of the Read trait in generalis the golang equivalent.
let bytes = std::fs::read(“path.txt”)?;
If you’re trying to actually do this in real code. The example is how you’d write this function yourself, but if you’re just trying to Get It Done, it’s significantly easier than the example.
[edited: I said there wasn't a io.ReadToEnd extracted from io.ReadFile in Go, but jatone pointed out it's called io.ReadAll.]