错误处理

Fleet 语言提供了强大而安全的错误处理机制,通过 OptionResult 类型来处理可能失败的操作,避免运行时崩溃。

📋 目录

🎯 错误处理哲学

Fleet 的错误处理原则

Fleet 采用显式错误处理,让错误成为类型系统的一部分:

// ❌ 传统方式 - 可能崩溃
fn divide_unsafe(a: int, b: int) -> int {
    return a / b;  // 如果 b 为 0 会崩溃
}

// ✅ Fleet 方式 - 安全处理
fn divide_safe(a: int, b: int) -> Option {
    if b == 0 {
        return Option::None;
    } else {
        return Option::Some(a / b);
    }
}

错误处理的优势

  1. 编译时检查 - 强制处理所有可能的错误
  2. 类型安全 - 错误信息包含在类型中
  3. 可组合性 - 错误处理可以链式组合
  4. 性能 - 零成本抽象,无运行时开销

🔍 Option 类型

Option 基础

Option 类型表示一个值可能存在也可能不存在:

enum Option {
    Some(int),  // 目前只支持具体类型,暂不支持泛型
    None,
}

fn find_user(id: int) -> Option {
    if id == 1 {
        return Option::Some(1);  // 返回用户ID,因为Option目前只支持int
    } else if id == 2 {
        return Option::Some(2);
    } else {
        return Option::None;
    }
}

fn main() {
    let user = find_user(1);
    match user {
        Option::Some(name) => print("Found user: " + name),
        Option::None => print("User not found"),
    }
}

Option 方法

fn main() {
    let maybe_number = Option::Some(42);
    let empty_option = Option::None;

    // is_some() 和 is_none()
    print("Has value: " + maybe_number.is_some());  // true
    print("Is empty: " + empty_option.is_none());   // true

    // unwrap() - 获取值(如果为 None 会 panic)
    let value = maybe_number.unwrap();
    print("Value: " + value);  // 42

    // unwrap_or() - 提供默认值
    let default_value = empty_option.unwrap_or(0);
    print("Default value: " + default_value);  // 0

    // unwrap_or_else() - 使用函数计算默认值
    let computed_default = empty_option.unwrap_or_else(|| {
        print("Computing default...");
        return 100;
    });
    print("Computed default: " + computed_default);  // 100
}

Option 链式操作

fn parse_number(s: str) -> Option {
    // 模拟解析数字
    if s == "42" {
        return Option::Some(42);
    } else {
        return Option::None;
    }
}

fn double(x: int) -> int {
    return x * 2;
}

fn main() {
    let input = "42";

    // map - 转换 Option 内部的值
    let doubled = parse_number(input).map(double);
    match doubled {
        Option::Some(value) => print("Doubled: " + value),  // 84
        Option::None => print("Failed to parse"),
    }

    // and_then - 链式操作
    let result = parse_number(input)
        .and_then(|x| {
            if x > 0 {
                return Option::Some(x * x);
            } else {
                return Option::None;
            }
        });

    print("Result: " + result.unwrap_or(0));  // 1764
}

Option 过滤

fn main() {
    let numbers = [
        Option::Some(1),
        Option::None,
        Option::Some(5),
        Option::None,
        Option::Some(10),
    ];

    // filter - 根据条件过滤
    let large_numbers = numbers
        .iter()
        .filter_map(|opt| opt.filter(|&x| x > 3))
        .collect();

    print("Large numbers: " + large_numbers);  // [5, 10]
}

⚠️ Result 类型

Result 基础

Result 类型表示操作可能成功或失败:

// 注意:Fleet 目前还未完全实现 Result 类型
// 以下是概念性示例,实际语法可能不同
enum Result {
    Ok(int),    // 成功值
    Err(str),   // 错误信息
}

fn divide(a: int, b: int) -> Result {
    if b == 0 {
        return Result::Err("Division by zero");
    } else {
        return Result::Ok(a / b);
    }
}

fn main() {
    let result1 = divide(10, 2);
    match result1 {
        Result::Ok(value) => print("Result: " + value),
        Result::Err(error) => print("Error: " + error),
    }

    let result2 = divide(10, 0);
    match result2 {
        Result::Ok(value) => print("Result: " + value),
        Result::Err(error) => print("Error: " + error),
    }
}

Result 方法

fn main() {
    let success = Result::Ok[int, str](42);
    let failure = Result::Err[int, str]("Something went wrong");

    // is_ok() 和 is_err()
    print("Is success: " + success.is_ok());  // true
    print("Is failure: " + failure.is_err()); // true

    // unwrap() 和 unwrap_err()
    let value = success.unwrap();
    print("Success value: " + value);  // 42

    let error = failure.unwrap_err();
    print("Error message: " + error);  // "Something went wrong"

    // unwrap_or() 和 unwrap_or_else()
    let safe_value = failure.unwrap_or(0);
    print("Safe value: " + safe_value);  // 0
}

Result 链式操作

fn parse_int(s: str) -> Result {
    if s == "42" {
        return Result::Ok(42);
    } else {
        return Result::Err("Invalid number");
    }
}

fn validate_positive(x: int) -> Result {
    if x > 0 {
        return Result::Ok(x);
    } else {
        return Result::Err("Number must be positive");
    }
}

fn main() {
    let input = "42";

    // map - 转换成功值
    let doubled = parse_int(input).map(|x| x * 2);
    print("Doubled: " + doubled.unwrap_or(0));  // 84

    // map_err - 转换错误值
    let with_context = parse_int("invalid")
        .map_err(|e| "Parse error: " + e);

    match with_context {
        Result::Ok(_) => print("Success"),
        Result::Err(e) => print(e),  // "Parse error: Invalid number"
    }

    // and_then - 链式操作
    let validated = parse_int(input)
        .and_then(validate_positive);

    match validated {
        Result::Ok(value) => print("Valid positive number: " + value),
        Result::Err(error) => print("Validation error: " + error),
    }
}

🔄 错误传播

? 操作符

? 操作符提供了简洁的错误传播方式:

fn parse_and_validate(s: str) -> Result {
    let number = parse_int(s)?;  // 如果失败,直接返回错误
    let positive = validate_positive(number)?;  // 链式传播
    return Result::Ok(positive);
}

// 等价于:
fn parse_and_validate_verbose(s: str) -> Result {
    match parse_int(s) {
        Result::Ok(number) => {
            match validate_positive(number) {
                Result::Ok(positive) => return Result::Ok(positive),
                Result::Err(error) => return Result::Err(error),
            }
        },
        Result::Err(error) => return Result::Err(error),
    }
}

fn main() {
    match parse_and_validate("42") {
        Result::Ok(value) => print("Success: " + value),
        Result::Err(error) => print("Error: " + error),
    }
}

错误转换

// 自动错误转换
fn complex_operation(s: str) -> Result {
    let number = parse_int(s)?;
    let validated = validate_positive(number)?;
    let doubled = multiply_by_two(validated)?;
    return Result::Ok(doubled);
}

// 手动错误转换
fn with_error_conversion(s: str) -> Result {
    let number = parse_int(s)
        .map_err(|e| CustomError::ParseError(e))?;

    let validated = validate_positive(number)
        .map_err(|e| CustomError::ValidationError(e))?;

    return Result::Ok(validated);
}

🎨 自定义错误类型

定义错误枚举

enum MathError {
    DivisionByZero,
    Overflow,
    InvalidInput(str),
}

impl Display for MathError {
    fn to_string(self) -> str {
        match self {
            MathError::DivisionByZero => return "Cannot divide by zero",
            MathError::Overflow => return "Arithmetic overflow",
            MathError::InvalidInput(msg) => return "Invalid input: " + msg,
        }
    }
}

fn safe_divide(a: int, b: int) -> Result {
    if b == 0 {
        return Result::Err(MathError::DivisionByZero);
    }

    let result = a / b;
    if result > 1000000 {
        return Result::Err(MathError::Overflow);
    }

    return Result::Ok(result);
}

fn main() {
    match safe_divide(10, 0) {
        Result::Ok(value) => print("Result: " + value),
        Result::Err(error) => print("Error: " + error.to_string()),
    }
}

错误链

enum DatabaseError {
    ConnectionFailed(str),
    QueryFailed(str),
    DataNotFound,
}

enum ServiceError {
    DatabaseError(DatabaseError),
    ValidationError(str),
    AuthenticationError,
}

fn fetch_user(id: int) -> Result {
    // 验证输入
    if id <= 0 {
        return Result::Err(ServiceError::ValidationError("Invalid user ID"));
    }

    // 查询数据库
    let user = query_database(id)
        .map_err(|db_err| ServiceError::DatabaseError(db_err))?;

    return Result::Ok(user);
}

fn main() {
    match fetch_user(-1) {
        Result::Ok(user) => print("Found user: " + user.name),
        Result::Err(ServiceError::ValidationError(msg)) => {
            print("Validation error: " + msg);
        },
        Result::Err(ServiceError::DatabaseError(db_err)) => {
            print("Database error: " + db_err.to_string());
        },
        Result::Err(ServiceError::AuthenticationError) => {
            print("Authentication failed");
        },
    }
}

🔄 错误恢复

重试机制

fn retry_operation(
    operation: fn() -> Result,
    max_attempts: int
) -> Result {
    var attempts = 0;

    loop {
        attempts = attempts + 1;

        match operation() {
            Result::Ok(value) => return Result::Ok(value),
            Result::Err(error) => {
                if attempts >= max_attempts {
                    return Result::Err(error);
                }
                print("Attempt " + attempts + " failed, retrying...");
            },
        }
    }
}

fn unreliable_network_call() -> Result {
    // 模拟不稳定的网络调用
    if random() < 0.7 {
        return Result::Err("Network timeout");
    } else {
        return Result::Ok("Success");
    }
}

fn main() {
    match retry_operation(unreliable_network_call, 3) {
        Result::Ok(data) => print("Got data: " + data),
        Result::Err(error) => print("Failed after retries: " + error),
    }
}

回退策略

fn get_data_with_fallback(source: DataSource) -> Result {
    // 尝试主要数据源
    match get_from_primary(source) {
        Result::Ok(data) => return Result::Ok(data),
        Result::Err(_) => {
            print("Primary source failed, trying cache...");

            // 尝试缓存
            match get_from_cache(source) {
                Result::Ok(data) => return Result::Ok(data),
                Result::Err(_) => {
                    print("Cache failed, using default...");

                    // 使用默认值
                    return Result::Ok(get_default_data());
                },
            }
        },
    }
}

📊 错误收集

收集多个错误

fn validate_user_data(data: UserData) -> Result> {
    var errors = [];

    // 验证姓名
    if data.name.is_empty() {
        errors.push("Name cannot be empty");
    }

    // 验证邮箱
    if !is_valid_email(data.email) {
        errors.push("Invalid email format");
    }

    // 验证年龄
    if data.age < 0 || data.age > 150 {
        errors.push("Age must be between 0 and 150");
    }

    if errors.is_empty() {
        return Result::Ok(ValidatedUser::from(data));
    } else {
        return Result::Err(errors);
    }
}

fn main() {
    let user_data = UserData {
        name: "",
        email: "invalid-email",
        age: -5,
    };

    match validate_user_data(user_data) {
        Result::Ok(user) => print("User validated successfully"),
        Result::Err(errors) => {
            print("Validation failed:");
            loop error in errors {
                print("  - " + error);
            }
        },
    }
}

🎯 最佳实践

错误处理指南

  1. 使用类型系统 - 让错误成为类型的一部分
  2. 提供上下文 - 错误信息应该有助于调试
  3. 及早失败 - 在错误发生时立即处理
  4. 文档化错误 - 说明函数可能返回的错误

性能考虑

// ✅ 好的做法 - 使用 Result 进行错误处理
fn parse_config(path: str) -> Result {
    let content = read_file(path)?;
    let parsed = parse_json(content)?;
    return Ok(Config::from(parsed));
}

// ❌ 避免的做法 - 使用异常(Fleet 不支持)
// fn parse_config_bad(path: str) -> Config {
//     let content = read_file(path);  // 可能抛出异常
//     let parsed = parse_json(content);  // 可能抛出异常
//     return Config::from(parsed);
// }

错误设计原则

  1. 具体而有用 - 提供足够的信息来诊断问题
  2. 可操作 - 用户应该知道如何修复错误
  3. 一致性 - 在整个应用中使用一致的错误处理模式
  4. 可组合 - 错误应该能够组合和转换

常见模式

// 模式 1: 转换和验证
fn process_input(input: str) -> Result {
    let cleaned = clean_input(input)?;
    let validated = validate_input(cleaned)?;
    let processed = transform_input(validated)?;
    return Result::Ok(processed);
}

// 模式 2: 资源管理
fn with_file(path: str, operation: fn(File) -> Result) -> Result {
    let file = open_file(path)?;
    let result = operation(file);
    close_file(file);
    return result;
}

// 模式 3: 条件错误
fn conditional_operation(condition: bool) -> Result {
    if condition {
        return Result::Ok("Success");
    } else {
        return Result::Err("Condition not met");
    }
}

🔗 相关主题

  • [基础语法>(basics.md) - 变量和基本概念
  • 类型系统 - 深入了解类型
  • 模式匹配 - 处理复杂数据结构
  • 示例程序 - 实际应用示例