rust-error-advanced
4
总安装量
3
周安装量
#49215
全站排名
安装命令
npx skills add https://github.com/huiali/rust-skills --skill rust-error-advanced
Agent 安装分布
trae-cn
2
claude-code
2
codebuddy
2
trae
1
qoder
1
antigravity
1
Skill 文档
æ·±å ¥é误å¤ç
æ ¸å¿é®é¢
è¿ä¸ªå¤±è´¥æ¯é¢æçè¿æ¯ bugï¼
é误å¤ççç¥å³å®ä»£ç çå¥å£®æ§ã
Result vs Option vs panic
| ç±»å | 使¶ä½¿ç¨ | ç¤ºä¾ |
|---|---|---|
Result<T, E> |
颿ä¼å¤±è´¥çæä½ | æä»¶è¯»åãç½ç»è¯·æ± |
Option<T> |
absence æ£å¸¸ | æ¥æ¾ãå¯è½ä¸ºç©ºçå¼ |
panic! |
bug æä¸åå¼è¿è§ | ç¨åºé»è¾é误ãä¸å¯æ¢å¤é误 |
unreachable!() |
ç论ä¸ä¸ä¼æ§è¡å°ç代ç | å¹é 穷举 |
é误å¤çå³ç
失败æ¯é¢æçåï¼
â
ââ æ¯ â è¿æ¯åºä»£ç ï¼
â ââ æ¯ â thiserrorï¼ç±»ååé误ï¼
â ââ å¦ â anyhowï¼æç¨æ§ï¼
â
ââ å¦ï¼absence æ£å¸¸ï¼
â ââ Option<T>
â
ââ å¦ï¼bug æä¸åå¼è¿è§
ââ panic!, assert!
thiserrorï¼åºä»£ç ï¼
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MyError {
#[error("validation failed: {0}")]
Validation(String),
#[error("IO error: {source}")]
Io {
#[from]
source: std::io::Error,
},
#[error("not found: {entity}:{id}")]
NotFound {
entity: String,
id: u64,
},
}
// ä½¿ç¨ ? ä¼ æ
fn read_config() -> Result<Config, MyError> {
let content = std::fs::read_to_string("config.toml")?;
Ok(toml::from_str(&content)?)
}
anyhowï¼åºç¨ä»£ç ï¼
use anyhow::{Context, Result, bail};
fn process_user(id: u64) -> Result<User> {
let user = db.find_user(id)
.with_context(|| format!("failed to find user {}", id))?;
if !user.is_active {
bail!("user {} is not active", id);
}
Ok(user)
}
// ç»åå¤ä¸ªé误æº
fn complex_operation() -> Result<()> {
let a = operation_a().context("operation A failed")?;
let b = operation_b().context("operation B failed")?;
Ok(())
}
é误设计åå
| åºæ¯ | 建议 |
|---|---|
| åºä»£ç | thiserrorï¼ç²¾ç¡®çé误类å |
| åºç¨ä»£ç | anyhowï¼æäºä¼ æåæ·»å ä¸ä¸æ |
| åºä¾èµåº | ä¼ éç¬¬ä¸æ¹é误ï¼#[from]ï¼ |
| éè¦é误ç | æä¸¾åä½ |
| éè¦éè¯¯é¾ | context() + with_context() |
常è§å模å¼
| 忍¡å¼ | é®é¢ | è§£å³ |
|---|---|---|
å¤å¤ unwrap() |
åºä¸ panic | ç¨ ? |
Box<dyn Error> |
丢失类åä¿¡æ¯ | thiserror åä½ |
| 丢失ä¸ä¸æ | è°è¯å°é¾ | .context() |
| é误åä½è¿å¤ | è¿åº¦è®¾è®¡ | ç®åæåå¹¶ |
panic 使ç¨åºæ¯
// 1. ä¸åééªè¯ï¼å
¬å¼ APIï¼
pub fn divide(a: f64, b: f64) -> f64 {
if b == 0.0 {
panic!("division by zero"); // å
¬å¼ APIï¼ç¡®ä¿è°ç¨è
ä¸ä¼ å
¥ 0
}
a / b
}
// 2. ä¸å¯æ¢å¤é误
fn start_engine() {
let config = load_critical_config();
if config.is_corrupted() {
panic!("cannot start without valid config");
}
}
// 3. å¹é
穷举ï¼ç论ä¸çæ°¸è¿æ§è¡ä¸å°ï¼
fn process_status(status: Status) {
match status {
Status::Running => { /* ... */ }
Status::Stopped => { /* ... */ }
// æªæ¥å¯è½æ·»å æ°ç¶æ
// _ => unreachable!("unknown status: {:?}", status),
}
}
// 4. å
é¨ä¸åé
assert!(!queue.is_empty(), "queue should never be empty here");
é误é¾
// ä½¿ç¨ map_err 转æ¢é误
fn high_level() -> Result<()> {
low_level()
.map_err(|e| MyError::from_low_level(e, "high level operation failed"))
}
// ä½¿ç¨ with_context æ·»å è°ç¨é¾ä¿¡æ¯
fn middle_layer() -> Result<()> {
low_level()
.with_context(|| format!("while processing request {}", request_id))?;
Ok(())
}
æä½³å®è·µ
- åºä»£ç ï¼ç²¾ç¡®çé误类åï¼thiserrorï¼
- åºç¨ä»£ç ï¼æç¨æ§ä¼å ï¼anyhowï¼
- ä¼ æé误ï¼ç¨
?èéunwrap() - æ·»å ä¸ä¸æï¼ä½¿ç¨
.context()æwith_context() - ä¿çé误æºï¼ç¨
#[from]ä¿çåºå±é误 - åºå panic åºæ¯ï¼bug ç¨ panicï¼é¢æå¤±è´¥ç¨ Result