質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

2回答

1431閲覧

rustでexpect("Err")の"Err"だけを出力したい

toriumi_haru

総合スコア26

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2020/06/27 14:51

rust

1let text:i32 = text.parse::<i32>().expect("Err"); 2

でtextが"hello"とかだと

thread 'main' panicked at 'Err: ParseIntError { kind: InvalidDigit }', src/main.rs:7:20 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

のようになりますが
"Err"のみをログに出すことはできますか

方法を教えて欲しいです。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんにちは。
回答の前にまずパニック(expectの中身)について認識をすりあわせたいです。

パニックは回復不能なエラー、プログラムのバグでないと起きえないことが起きたときに使う回復不能なエラーです(参考 panic!で回復不能なエラー)。他の言語でいう例外は Result 型が担当するので、例外のような気持で使うものではありません。なのでパニックを使いつつユーザフレンドリなエラーメッセージを残そうとしているときは、使い方を間違っている可能性があります。

このような前提の下で、もしやりたいことが「エラーメッセージを出して終了したい」だけならパニックを使わずに以下のような書き方があります。

rust

1use std::process::exit; 2 3let text = match text.parse::<i32>() { 4 Ok(text) => text, 5 Err(_) => { 6 // エラー出力にログを出す 7 eprintln!("Err"); 8 // プログラムをエラー終了する 9 exit(1) 10 } 11};

さらにもし、やりたいことが「"Err" をログに出す」だけが目的なら exit を呼ぶのは不適当です。 exit を呼んだらプログラムが終了してしまいます。
とはいえ、エラーだと数値が取り出せないので適当なエラー値を返して関数から抜けることになるかと思います。

rust

1use std::error::Error as StdError; 2use std::fmt; 3 4// 関数か抜けるときの値を用意 5#[derive(Debug)] 6enum Error { 7 UserInputError 8} 9 10impl fmt::Display for Error { 11 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 12 match self { 13 Error::UserInputError => write!(f, "Err"), 14 } 15 } 16} 17 18// エラーを実装しておくと扱いやすい 19impl StdError for Error {} 20 21// 処理する関数 22fn hogehoge(text: String) -> Result<i32, Error> { 23 let text = match text.parse::<i32>() { 24 Ok(text) => text, 25 Err(_) => { 26 eprintln!("Err"); 27 return Err(Error::UserInputError); 28 } 29 }; 30 Ok(text) 31}

ここでは文脈がないので Error を定義して返しましたが、もし文脈的に io::Error が適当なら io::Error を返してもいいです。

最後に、もし本当に回復不能なエラーを使った上で、それを処理したいという特殊用途であれば std::panic::set_hook がありますが、メッセージだけを取り出すのは難しそうでした。

rust

1use std::panic; 2 3fn main() { 4 panic::set_hook(Box::new(|panic| { 5 if let Some(payload) = panic.payload().downcast_ref::<String>() { 6 eprintln!("{}", payload); 7 } else { 8 eprintln!("{}", panic); 9 } 10 })); 11 12 let text = "hello"; 13 let text = text.parse::<i32>().expect("Err"); 14} 15

console

1Err: ParseIntError { kind: InvalidDigit }

exit を呼ぶ方法、Error を定義して関数から抜ける方法、パニックハンドラを使う方法の3つを提示しましたが、恐らく exit を呼ぶ方法が無難だと思います。
複雑なことをやりはじめたら Error を定義して使う方法に移行して下さい。 Error を定義して使う方法は公式ドキュメントなどを参考にして下さい: Resultで回復可能なエラー

投稿2020/06/28 02:51

blackenedgold

総合スコア468

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

toriumi_haru

2020/06/28 03:05

様々な方法を提示していただいてありがとうございます! これから場面に合わせて使い分けてみようと思います!
guest

0

std::panic::set_hookを使えば可能です。

panic!.expect(_)todo!unreachable!だとPanicInfo::payload&'static strStringなので、std::any::Any::downcast_refで条件分岐すれば良いです。

rust

1use std::panic; 2 3panic::set_hook(Box::new(|panic| { 4 if let Some(payload) = panic.payload().downcast_ref::<&str>() { 5 eprintln!("{}", payload); 6 } else if let Some(payload) = panic.payload().downcast_ref::<String>() { 7 eprintln!("{}", payload); 8 } else { 9 eprintln!("{}", panic); 10 } 11})); 12 13panic!("Panic message");

text

1$ cargo run 2 Compiling a v0.0.0 (/home/ryo/src/local/scripts/rs/a) 3 Finished dev [unoptimized + debuginfo] target(s) in 0.31s 4 Running `/home/ryo/src/local/scripts/rs/target/debug/a` 5Panic message

(追記1) ParseIntErrorを無視するなら.expect("メッセージ")のかわりに.ok().expect("メッセージ")か、.unwrap_or_else(|_| panic!("メッセージ"))とすれば良いです。

(追記2) .ok().expect(_)はClippy (Rustツールチェインに付いてくるlint)のwarning対象のようです。

ところで前の質問でのコードでも触れましたが、mainの返り値には()の他にResult<(), E> (E: Debug)が使えます。 こちらを使うことをおすすめします。

mainの返り値をResultして実際にErrが返される場合、Error: {Debug表記}というエラーメッセージになります。

rust

1use std::fmt; 2 3fn main() -> Result<(), MyError> { 4 Err(MyError) 5} 6 7struct MyError; 8 9impl fmt::Debug for MyError { 10 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 11 write!(fmt, "Debug表記") 12 } 13}

text

1$ cargo run 2 Compiling a v0.0.0 (/home/ryo/src/local/scripts/rs/a) 3 Finished dev [unoptimized + debuginfo] target(s) in 0.24s 4 Running `/home/ryo/src/local/scripts/rs/target/debug/a` 5Error: Debug表記

(Result<(), String>Resutl<() &'static str>とした場合、Error: "エラーメッセージ"のように""付きで表示されてしまいます。)

現在(特に小規模なアプリケーションでは)エラー型にanyhow::Errorを使うことが推奨されています。 anyhow::ErrorDebug表示では中身のエラーはDebugではなくDisplayで表示されます。 またstd::error::Error::sourceの内容も表示してくれます。

(追記1) このコードを貼るのを忘れてました...

rust

1use anyhow::Context as _; 2use std::fs; 3 4fn main() -> anyhow::Result<()> { 5 let _content = fs::read_to_string("./nonexisting-file") 6 .with_context(|| "Failed to read ./nonexisting-file")?; 7 8 Ok(()) 9}

text

1$ cargo add anyhow 2 Updating 'https://github.com/rust-lang/crates.io-index' index 3 Adding anyhow v1.0.31 to dependencies 4$ cargo run 5 Compiling a v0.0.0 (/home/ryo/src/local/scripts/rs/a) 6 Finished dev [unoptimized + debuginfo] target(s) in 0.32s 7 Running `/home/ryo/src/local/scripts/rs/target/debug/a` 8Error: Failed to read ./nonexisting-file 9 10Caused by: 11 No such file or directory (os error 2)

投稿2020/06/27 17:30

編集2020/06/27 18:03
qryxip

総合スコア86

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

qryxip

2020/06/27 17:41

質問は > "Err"のみをログに出すことはできますか でしたね。 `ParseIntError`を無視するなら`.expect("メッセージ")`のかわりに`.unwrap_or_else(|| panic!("メッセージ"))`とすることで可能です。 あと最後の例、このコードを貼るのを忘れてました... ```rust use anyhow::Context as _; use std::fs; fn main() -> anyhow::Result<()> { let _content = fs::read_to_string("./nonexisting-file") .with_context(|| "Failed to read ./nonexisting-file")?; Ok(()) } ```
qryxip

2020/06/27 17:48

回答の編集ができるようなので編集で追記しました。
toriumi_haru

2020/06/28 03:07

こちらの質問にも回答していただきありがとうございます! rustはまだthe bookのエラー処理の前までしか読めておらず、まだまだわからないことが多いのでこれからも教えてくださると嬉しいです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問