Rustのエラー
Rustには回復不能なエラーと回復可能なエラーがある
また、RustはGo言語と同じように、try catchでエラー処理をしない
※環境変数でRUST_BACKTRACE=1を設定するとバックトレースが出力される
回復不能なエラー
panic!を使う or 何かしらの大きなエラーが出る(例: vec!で無効な要素にアクセスしようとする等)
code:panic-error.rs
fn main() {
panic!("もう無理ぽ");
}
// thread 'main' panicked at 'もう無理ぽ', **.rs:*:* ※*はファイル名や行など
回復可能なエラー
Result<成功した場合の型, 失敗した場合の型>を使うとできる
※要事前知識: RustのMatch
※補足知識: Rust "if let"(if letでもエラーの処理もできる)
code:result.rs
// Resultが返る関数(サンプルとして用意)
fn res(is_ok: bool) -> Result<bool, String> {
if is_ok {
Ok(true)
} else {
Err(String::from("OKじゃなかったのでエラー"))
}
}
fn main() {
let r = res(false); // ここでの返り値は: Err("OKじゃなかったのでエラー")
let r = match r { // matchを使ってOkかErrを判別する
Ok(res) => res, // Okだったときの処理。この場合はOkの中身を返す
Err(err_res) => { // Errだったときの処理
// 例としてパニック(回復不能なエラー)を出す
panic!("res関数でエラー: {}", err_res);
}
};
println!("{}", r);
}
Rust Playgroundで試す
複数のErrが出ることがありうる場合は以下のようにする ※Errの型による
code:result-err-multiple.rs
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let _f = File::open("hello.txt");
let _f = match _f {
Ok(file) => file,
// 内容を借用してその内容(enum)がNotFoundだったらこの結果
Err(ref error) if error.kind() == ErrorKind::NotFound => {
panic!("ファイルが見つからなかった")
},
// ↑以外のエラーが発生した場合はこれを返す
Err(error) => {
panic!(
"ファイルが開けなかったor問題が発生した: {:?}",
error
)
},
};
}
エラー移譲のショートカット
関数とかのあとに?をつけるとその関数で起きたErrをそのまま受け流す
返す型がResult<T, E>内の関数内で使える
?のあとに関数をつけても問題ない
例: File::open("example.txt")?.read_to_string(&mut s)?;
code:err-transfer.rs
use std::io;
use std::fs::File;
use std::io::Read;
fn read_file() -> Result<String, io::Error> {
let mut f = File::open("example.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
fn main() {
let read_string = read_file();
match read_string {
Ok(s) => println!("{}", s),
Err(err) => println!("読めなかったよ: {:?}", err)
};
}
Rust Playgroundで試す
unwrapとexpect
エラーのショートカット。
unwrap
Result<T, E>やOption<T>などで使える関数
※Option<T>についてはRust Optionを参照
結果の中身を取り出すのを試みる。取り出せない場合(ErrやNone)の場合はパニックが発生する
code:error-via-unwrap.rs
use std::fs::File;
fn main() {
let _f = File::open("hello.txt").unwrap(); // hello.txtが見つからないとエラー(パニック)
}
パニックを出す代わりにunwrap_orを使うとErrだった場合はunwrap_or内で定義した内容が返る
code:error-via-unwrap_or.rs
fn ok_err(bl: bool) -> Result<i32, ()> {
if bl {
Ok(1)
} else {
Err(())
}
}
fn main() {
let sn_t = ok_err(true).unwrap_or(0i32); // Okが返るのでその中身を返す
let sn_f = ok_err(false).unwrap_or(0i32); // Errが返るのでunwrap_orの値を返す
println!("{}", sn_t); // 1
println!("{}", sn_f); // 0
}
Rust Playgroundで試す
expect
任意のエラーメッセージを定義できる
ErrやNoneだった場合に、このメッセージのパニックが発出される
code:error-via-expect.rs
use std::fs::File;
fn main() {
let _f = File::open("hello.txt").expect("開くことができなかった");
}
#Rust