anyhow::Context
在 C 中錯誤處理通常是這樣:
if (read(fd, buf, len) < 0) {
return -1;
}
// 更進階一點
FILE *fp = fopen(path, "r");
if (!fp) {
perror("fopen failed");
return -1;
}
為了更好的捕捉錯誤,去實現 錯誤棧 (Error Stack) 去傳遞錯誤,我們可以實作 Context:
- 讓錯誤以錯誤碼呈現,實現 Error is a value
- 讓錯誤可以被包裝(wrap)
- 錯誤可以一路往上拋
typedef struct Error {
int code;
const char *message;
const char *context;
} Error;
// 不再只回傳錯誤碼 -1,而是回傳一個 Error*
Error *error_with_context(Error *inner, const char *ctx) {
Error *err = malloc(sizeof(Error));
err->code = inner->code;
err->message = inner->message;
err->context = ctx;
return err;
}
Error *err = init_system();
if (err) {
printf("Error: %s\nContext: %s\n", err->message, err->context);
}
而在 Rust 中只要一行就能搞定:
init_system().with_context(|| "初始化系統失敗").map_err(|e| eprintln!("{:#}", e)).ok();