このコードはなぜコンパイルされないのでしょうか?
use std::{fs, path::Path};
fn main() {
let dir = Path::new("../FileSystem");
if !dir.is_dir() {
println!("Is not a directory");
return;
}
for item in try!(fs::read_dir(dir)) {
let file = match item {
Err(e) => {
println!("Error: {}", e);
return;
}
Ok(f) => f,
};
println!("");
}
println!("Done");
}
これは私が受け取ったエラーです
error[E0308]: mismatched types
--> src/main.rs:11:17
|
11 | for item in try!(fs::read_dir(dir)) {
| ^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result`
|
= note: expected type `()`
found type `std::result::Result<_, _>`
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
疑問符演算子も試してみました:
for item in fs::read_dir(dir)? {
別のエラーが発生しました:
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:11:17
|
11 | for item in fs::read_dir(dir)? {
| ^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
Rustの以前のバージョンでは、同様のエラーが発生していました。std::ops::Carrier
try!()
と は避けるべきでしょうか?
? エラーを処理する最善の方法は何でしょうか? ほとんどの場合、次のようにします:
match error_prone {
Err(e) => {
println!("Error: {}", e);
return;
},
Ok(f) => f,
};
しかし、それをループで使用しなければならない場合for
、それは完全に混乱します
for i in match error_prone {
// match code
} {
// loop code
}
ベストアンサー1
try!
Err
は自動的にsを返すマクロです。?
はほぼ同じことを行う構文ですが、を実装する任意の型で動作します。Try
特性。
現在ラスト 1.22.0はをOption
実装しているTry
ので、 で使用できます?
。それ以前は、?
は を返す関数でのみ使用できましたResult
。try!
は引き続き でのみ機能しますResult
。
現在ラスト 1.26.0は、main
を実装する値を返すことが許可されていますTermination
。それ以前は、値は返されません。
Rust 1.26.0 時点
main
を返すようにマークし、すべての「成功」ケースでResult
return すると、元のコードは機能します。Ok(())
use std::{fs, io, path::Path};
fn main() -> Result<(), io::Error> {
let dir = Path::new("../FileSystem");
if !dir.is_dir() {
println!("Is not a directory");
return Ok(());
}
for item in fs::read_dir(dir)? {
let file = match item {
Err(e) => {
println!("Error: {}", e);
return Ok(());
}
Ok(f) => f,
};
println!("");
}
println!("Done");
Ok(())
}
それ以前は
次のようにコードを変換すると、次のようになります?
。
use std::{error::Error, fs, path::Path};
fn print_dir_contents() -> Result<String, Box<Error>> {
let dir = Path::new("../FileSystem");
if !dir.is_dir() {
return Err(Box::from("Is not a directory!"));
}
for 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()),
}
}
ここでは予想外のエラー処理がたくさんあります。他の言語ではエラー処理は必要ないことが多いです。しかし、他の言語にはエラー処理が存在します。Rust ではエラー処理がわかるようになっています。エラーは次のとおりです。
entry?
反復中に IO エラーが発生する可能性があります。
path.file_name().unwrap()
すべてのパスにファイル名があるわけではありません。ファイル名のないパスは返されないunwrap
ため、これが可能です。read_dir
file_name.to_string_lossy()
to_str
エラーをスローすることもできますが、このようにする方が適切です。このエラーは、すべてのファイル名が有効な Unicode ではないために発生します。
try!
そして、?
エラーを に変換して戻り値にスローしますBox::Error
。実際には、問題が発生する可能性のあるすべてのものを統合したエラーを返す方が合理的です。幸いなことに、io::Error
はちょうど適切な型です。
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 a directory!"));
}
// ...
}
しかし、率直に言うと、このチェックはすでに に含まれているfs::read_dir
ので、 をif !dis.is_dir
完全に削除するだけで済みます。
use std::{fs, io, path::Path};
fn print_dir_contents() -> Result<String, io::Error> {
let dir = Path::new("../FileSystem");
for 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()),
}
}