跳到正文
本頁目錄

Expected(錯誤處理)

ll/api/Expected.h · 通用

概述

Expected 模塊提供了 LeviLamina 的錯誤處理原語:Expected<T>(基於 nonstd::expected 的值或錯誤類型)、Error(多態錯誤容器)以及用於創建和傳播錯誤的輔助函數。

頭文件

頭文件說明
ll/api/Expected.hExpected<T>、Error、ErrorInfoBase 及工廠函數

核心類型

Expected<T>

C++
namespace ll {
template <class T = void>
using Expected = nonstd::expected<T, ll::Error>;
}
  • Expected<T> — 持有類型 T 的值或 ll::Error
  • Expected<> — 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("初始化失败");
}

相關模塊