Expected(錯誤處理)
ll/api/Expected.h · 通用
概述
Expected 模塊提供了 LeviLamina 的錯誤處理原語:Expected<T>(基於 nonstd::expected 的值或錯誤類型)、Error(多態錯誤容器)以及用於創建和傳播錯誤的輔助函數。
頭文件
| 頭文件 | 說明 |
|---|---|
ll/api/Expected.h | Expected<T>、Error、ErrorInfoBase 及工廠函數 |
核心類型
Expected<T>
C++
namespace ll {
template <class T = void>
using Expected = nonstd::expected<T, ll::Error>;
}Expected<T>— 持有類型T的值或ll::ErrorExpected<>—Expected<void>的別名,表示成功或錯誤(無返回值)
Error
僅可移動的錯誤容器,包裝多態 ErrorInfoBase。
C++
namespace ll {
class Error {
public:
Error() noexcept = default;
Error(std::unique_ptr<ErrorInfoBase> info) noexcept;
explicit operator bool() const noexcept; // 有错误时为 true
std::string message() const noexcept;
template <class T> bool isA() noexcept;
template <class T> T& as() noexcept;
Error& join(Error) noexcept;
Error const& log(io::Logger&, io::LogLevel = io::LogLevel::Error) const noexcept;
Error const& log(CommandOutput&, CommandOutputMessageType = CommandOutputMessageType::Error) const noexcept;
};
}ErrorInfoBase
錯誤詳情的抽象基類。子類化以創建自定義錯誤類型。
C++
namespace ll {
class ErrorInfoBase {
public:
virtual ~ErrorInfoBase();
virtual std::string message() const noexcept = 0;
};
}內置錯誤類型
| 類型 | 說明 |
|---|---|
StringError | 包裝 std::string 消息 |
ErrorCodeError | 包裝 std::error_code |
工廠函數
C++
namespace ll {
// 从错误子类创建 Unexpected
template <std::derived_from<ErrorInfoBase> T, class... Args>
Unexpected makeError(Args&&... args) noexcept;
// 字符串错误的快捷方式
Unexpected makeStringError(std::string str) noexcept;
// error_code 错误的快捷方式
Unexpected makeErrorCodeError(std::error_code ec) noexcept;
Unexpected makeErrorCodeError(std::errc ec) noexcept;
// 将当前异常捕获为错误
Unexpected makeExceptionError(std::exception_ptr const& = std::current_exception()) noexcept;
// 转发现有错误
Unexpected forwardError(Error& err) noexcept;
}使用方法
返回錯誤
C++
#include "ll/api/Expected.h"
ll::Expected<int> divide(int a, int b) {
if (b == 0) {
return ll::makeStringError("除以零");
}
return a / b;
}處理錯誤
C++
#include "ll/api/Expected.h"
#include "ll/api/io/Logger.h"
void example(ll::io::Logger& logger) {
auto result = divide(10, 0);
if (!result) {
result.error().log(logger);
return;
}
logger.info("结果: {}", *result);
}自定義錯誤類型
C++
#include "ll/api/Expected.h"
struct FileNotFoundError : ll::ErrorInfoBase {
std::string path;
FileNotFoundError(std::string path) : path(std::move(path)) {}
std::string message() const noexcept override {
return "文件未找到: " + path;
}
};
ll::Expected<std::string> readFile(std::string const& path) {
// ...
return ll::makeError<FileNotFoundError>(path);
}
void handleError() {
auto result = readFile("missing.txt");
if (!result) {
if (result.error().isA<FileNotFoundError>()) {
auto& err = result.error().as<FileNotFoundError>();
// 访问 err.path
}
}
}傳播錯誤
C++
#include "ll/api/Expected.h"
ll::Expected<int> computeSum(int a, int b) {
auto x = divide(a, 2);
if (!x) return ll::forwardError(x.error());
auto y = divide(b, 3);
if (!y) return ll::forwardError(y.error());
return *x + *y;
}Void Expected
C++
#include "ll/api/Expected.h"
ll::Expected<> initialize() {
// 做一些可能失败的操作
return {}; // 成功
}
ll::Expected<> initializeWithError() {
return ll::makeStringError("初始化失败");
}相關模塊
- IO & Logger(輸入輸出與日誌) —
Error::log()輸出到 Logger - Mod(模組系統) — 模組生命週期回調返回
Expected<>