[英]What is the best way of handling error in rust? (CLI with clap)
我正在嘗試使用 clap 在 rust 中開發一個簡單的 cli 賬單管理器。 我想讓用戶通過輸入其名稱和價值來添加新賬單,刪除一些賬單,我還想添加撤消和重做功能。 因為這是我在 rust 的第一個項目,所以我把它命名為 p1。 在終端中,用戶必須這樣做:
p1 -n bill1 -v 50
然后,該法案將被添加或
p1 undo 5
然后,最后 5 個操作將被撤消。 但是,由於 clap 的正常功能,至少據我所知,這種行為也被接受:
p1 -n bill2 -v 30 redo 30
我不想允許它。 我不想讓用戶同時使用標志和子命令。 所以我做了一些驗證。 為了讓您更容易幫助我,我將展示代碼的相關部分。
use clap::{Parser, Subcommand};
use std::{collections::HashMap, path::PathBuf};
use home::home_dir;
use std::fs;
#[derive(Parser, Debug)]
struct Args {
/// The name of the bill
#[clap(short, long, value_parser)]
name: Option<String>,
/// The value of the bill
#[clap(short, long, value_parser)]
value: Option<u32>,
#[clap(subcommand)]
command: Option<Commands>,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Undo
Undo { undo: Option<u32> },
/// Redo
Redo { redo: Option<u32> },
/// Remove
Remove { remove: Option<String> },
}
fn validate_args(args: Args) -> Result<Args, String> {
match (&args.name, &args.value, &args.command) {
(Some(_), Some(_), None) => Ok(args),
(None, None, Some(_)) => Ok(args),
(None, None, None) => Ok(args),
_ => Err("You can't use options and subcommands at the same time".to_string())
}
}
fn exit_on_error(error: &Result<Args, String>) {
println!("{:?}", error);
panic!("aaaaaaaaaaaaaaaaaa");
}
fn main() {
let args: Result<Args, String> = validate_args(Args::parse());
match args {
Ok(_) => (),
Err(_) => exit_on_error(&args)
};
...
}
我需要幫助的另一件事是。 當用戶既不插入標志也不插入子命令時,只需在終端中輸入“p1”,我想將他重定向到幫助子命令,就好像他輸入了
p1 help
我該怎么做?
而且,我仍然不習慣 rust 風格的可變擁有手柄。 “exit_on_error” function 只能接收借來的結果,因為顯然字符串無法實現 Copy。 這可以防止我在打印之前解開 Err,這使得它在終端中顯示為帶引號。 我應該怎么做才能解決它?
請幫助我,如果我的問題有什么不清楚的地方,請告訴我。
我同意@SirDarius 的觀點,您可能不應該這樣做,但是,嗯,並不意味着知道如何做到這一點會很痛苦:
當用戶既不插入標志也不插入子命令時,只需在終端中輸入“p1”,我想將他重定向到幫助子命令,就好像他輸入了
p1 help
如果很難知道是否從解析的Args
中傳遞了任何 arguments,例如,您可以回避clap
並檢查來自std::env::args()
的參數計數
if std::env::args().count() <= 1 {
Args::parse_from(&[
// Argument 0 is always the program name.
// Could just use "p1" here, but this is more generic:
std::env::args()
.next()
.as_ref()
.map(String::as_str)
.unwrap_or(env!("CARGO_CRATE_NAME")),
// as if help was typed:
"help",
]);
unreachable!("Should print help and exit");
}
我認為您也可以使用 clap 的ArgGroup
來實現這種行為,但我發現它們很笨重。
而且,我仍然不習慣 rust 風格的可變擁有手柄。
這是一個經典的 Rust 問題,您可以做很多事情:
validate_args
即可。 這也是Args::parse
所做的。let args = match args { Ok(args) => args, Err(e) => exit_on_error(e) };
(必須為此更改exit_on_error
的類型。)exit_on_error
具有類型fn(Result<Args, String>) -> Args
並將match
移動到其中。main
return Result<(), Box<dyn std::error::Error>>
這樣你就可以使用?
解開Result
s(盡管您需要選擇具有良好Display
實現類型而不是String
的不同錯誤類型。不妨使用anyhow
板條箱。)error.as_ref().err().unwrap()
(您甚至可以添加Option::cloned
以獲得錯誤字符串的自有副本。)最后:請在 StackOverflow 上對每個問題提出一個問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.