Ответ 1
try!
- макрос, который автоматически возвращает Err
; ?
это синтаксис, который делает в основном одно и то же, но он работает с любым типом, который реализует свойство Try
.
Начиная с Rust 1.22.0, Option
реализует Try
, поэтому его можно использовать ?
, До этого ?
может использоваться только в функциях, возвращающих Result
. try!
продолжает работать только с Result
s.
Начиная с Rust 1.26.0, main
разрешено возвращать значение, которое реализует Termination
. До этого он не возвращает никакой ценности.
Начиная с Rust 1.26.0
Ваш исходный код работает, если вы помечаете main
как возвращающий Result
и затем возвращаете 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?
Ошибки ввода-вывода могут возникать во время итерации.
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()),
}
}