rust - Why do try!() and ? not compile when used in main? -
why code not compile?
use std::io; use std::fs; use std::path::path; fn main() { // open path let dir = path::new("../filesystem"); // check if directory if !dir.is_dir() { println!("is not directory"); return; } item in try!(fs::read_dir(dir)) { let file = match item { err(e) => { println!("error: {}", e); return; } ok(f) => f, }; println!(""); } println!("done"); }
this error get
error[e0308]: mismatched types --> src/main.rs:15:17 | 15 | item in try!(fs::read_dir(dir)) { | ^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::result` | = note: expected type `()` found type `std::result::result<_, _>` = help: here functions might fulfill needs: - .unwrap() - .unwrap_err() - .unwrap_or_default() = note: error originates in macro outside of current crate
i think complaining line: for item in try!(fs::read_dir(dir))
i tried question mark operator:
for item in fs::read_dir(dir)? {
which had different error:
error[e0277]: trait bound `(): std::ops::try` not satisfied --> src/main.rs:15:17 | 15 | item in fs::read_dir(dir)? { | ------------------ | | | trait `std::ops::try` not implemented `()` | in macro invocation | = note: required `std::ops::try::from_error`
previous versions of rust had similar error std::ops::carrier
should avoid try!()
, ?
? best way handle errors? this:
match error_prone { err(e) => { println!("error: {}", e); return; }, ok(f) => f, };
but if have use in loop, it's complete mess
for in match error_prone { // match code } { // loop code }
try!
macro returns err
s automatically; ?
syntax same thing. both can used in functions return result
(until rfc 1859 implemented). main
doesn't return value (until rfc 1937 implemented).
this how might transform code use ?
:
use std::error::error; use std::fs; use std::path::path; fn print_dir_contents() -> result<string, box<error>> { // open path let dir = path::new("../filesystem"); // check if directory if !dir.is_dir() { return err(box::from("is not directory!")); } entry in fs::read_dir(dir)? { let path = entry?.path(); let file_name = path.file_name().unwrap(); println!("{}", file_name.to_string_lossy()); } ok("done".into()) } fn main() { match print_dir_contents() { ok(s) => println!("{}", s), err(e) => println!("error: {}", e.to_string()), } }
there's lot of error handling here might not expect - other languages don't tend require it! exist in other languages - rust makes know it. here errors:
entry?
io errors can happen during iteration.
path.file_name().unwrap()
not paths have file names. can unwrap
because read_dir
won't give path without file name.
file_name.to_string_lossy()
you can to_str
, throw error, it's nicer this. error exists because not file names valid unicode.
try!
, ?
throw errors return value, converting them box::error
. it's more reasonable return amalgamated error of things can go wrong. luckily io::error
right type:
use std::io; ... fn print_dir_contents() -> result<string, io::error> { ... if !dir.is_dir() { return err(io::error::new(io::errorkind::other, "is not directory!")); } ... }
frankly, though, check in fs::read_dir
, can remove if !dis.is_dir
altogether:
use std::io; use std::fs; use std::path::path; fn print_dir_contents() -> result<string, io::error> { // open path let dir = path::new("../filesystem"); entry in fs::read_dir(dir)? { let path = entry?.path(); let file_name = path.file_name().unwrap(); println!("{}", file_name.to_string_lossy()); } ok("done".into()) } fn main() { match print_dir_contents() { ok(s) => println!("{}", s), err(e) => println!("error: {}", e.to_string()), } }
Comments
Post a Comment