错误处理
Valkyrie 使用 try 语句和 catch 机制来处理错误。try 是一个独立的语句,可以与类型系统结合使用。
Try 语句
基本 Try 语法
valkyrie
# try 是独立语句,返回 Result 类型
let result = try Result<String> {
read_file("config.txt")?
}
# 带错误类型的 try
let data = try Result<Data, ParseError> {
let content = read_file("data.json")?
parse_json(content)?
}
# 简化形式
let value = try {
risky_operation()?
}Try 与 Option 类型
valkyrie
# 处理可能失败的操作
let maybe_value = try Option<i32> {
let input = get_user_input()?
parse_number(input)?
}
# 链式操作
let result = try Option<User> {
let id = extract_user_id(request)?
let user = find_user_by_id(id)?
validate_user(user)?
}Catch 处理
非主干控制流 Catch
valkyrie
# 使用 .catch 处理错误
let config = try Result<Config> {
read_config_file()?
}
.catch {
case FileNotFound(path): create_default_config(path)
case ParseError(msg):
log_error(msg)
Config::default()
case error:
print("Unexpected error: ${error}")
Config::empty()
}
# 命名 catch
let data = try Result<Data> {
fetch_remote_data()?
}
catch network_error {
case TimeoutError: retry_with_backoff()
case ConnectionError(msg): use_cached_data()
case error:
log_error(error)
Data::empty()
}Match 风格的 Catch
valkyrie
# catch 和 match 是对偶的,能力一模一样
let user_data = try Result<UserData> {
let raw = fetch_user_data(user_id)?
validate_and_parse(raw)?
}
.catch {
case ValidationError { field, message }:
show_field_error(field, message)
UserData::guest()
case NetworkError { code, .. } if code >= 500:
# 服务器错误,稍后重试
schedule_retry()
UserData::cached(user_id)
case NetworkError { code, .. } if code >= 400:
# 客户端错误
UserData::error(code)
else: UserData::unknown_error()
}错误传播
问号操作符
valkyrie
# ? 操作符用于错误传播
micro process_file(path: String) -> Result<String, FileError> {
let content = read_file(path)? # 如果失败,直接返回错误
let processed = transform_content(content)?
validate_result(processed)?
}
# 在 try 块中使用
let final_result = try Result<ProcessedData> {
let raw = fetch_data()?
let cleaned = clean_data(raw)?
let validated = validate_data(cleaned)?
process_final(validated)?
}错误转换
valkyrie
# 自动错误转换
micro read_and_parse(path: String) -> Result<Config, AppError> {
try Result<Config, AppError> {
let content = read_file(path)? # FileError -> AppError
let config = parse_json(content)? # ParseError -> AppError
validate_config(config)? # ValidationError -> AppError
}
}
# 手动错误转换
let result = try Result<Data> {
fetch_data().map_err({ $e => AppError::Network($e) })?
}自定义错误类型
valkyrie
# 定义错误类型
union AppError {
Network(NetworkError),
Parse(ParseError),
Validation { field: String, message: String },
IO(IOError)
}
# 实现错误转换
imply From<NetworkError> for AppError {
from(err: NetworkError) -> AppError {
AppError::Network(err)
}
}
# 使用自定义错误
micro load_user_config(user_id: String) -> Result<UserConfig, AppError> {
try Result<UserConfig, AppError> {
let path = get_config_path(user_id)?
let content = read_file(path)?
let config = parse_config(content)?
validate_user_config(config)?
}
}错误恢复模式
回退策略
valkyrie
# 多级回退
let avatar = try Option<Image> {
load_from_cdn(user_id)?
}
.catch {
case NetworkError: try Option<Image> {
load_from_cache(user_id)?
}
.catch {
case CacheError: Some(default_avatar())
else: None
}
else: Some(default_avatar())
}
# 重试机制
let data = try Result<Data> {
fetch_with_retry(url, max_retries = 3)?
}
.catch {
case RetryExhausted(attempts):
log_error("Failed after ${attempts} attempts")
use_fallback_data()
case error:
log_error("Unexpected error: ${error}")
Data::empty()
}部分恢复
valkyrie
# 处理部分失败
let results = try Result<Vector<ProcessedItem>> {
items.map({ $item =>
try Result<ProcessedItem> {
process_item($item)?
}
.catch {
case ProcessingError(msg):
log_warning("Skipping item: ${msg}")
None # 跳过失败的项目
else: None
}
}).filter_map({ $x => $x }).collect()
}最佳实践
1. 错误类型设计
valkyrie
# 结构化错误信息
union ValidationError {
Required { field: String },
Invalid { field: String, value: String, reason: String },
TooLong { field: String, max_length: usize, actual: usize },
TooShort { field: String, min_length: usize, actual: usize }
}
# 上下文信息
class ContextualError {
operation: String,
context: Map<String, String>,
source: Box<dyn Error>
}2. 错误处理策略
valkyrie
# 就近处理
micro validate_user_input(input: UserInput) -> Result<ValidatedInput, ValidationError> {
try Result<ValidatedInput> {
let email = validate_email(input.email)?
let age = validate_age(input.age)?
let name = validate_name(input.name)?
new ValidatedInput { email, age, name }
}
}
# 统一错误处理
micro main() {
let result = try Result<()> {
run_application()?
}
.catch {
case ConfigError(msg):
eprintln("Configuration error: ${msg}")
exit(1)
case NetworkError(msg):
eprintln("Network error: ${msg}")
exit(2)
case error:
eprintln("Unexpected error: ${error}")
exit(99)
}
}3. 资源管理
valkyrie
# 使用 RAII 模式
class FileHandle {
path: String,
handle: File
}
imply Drop for FileHandle {
drop() {
self.handle.close()
}
}
# 安全的资源使用
micro process_file_safely(path: String) -> Result<String, FileError> {
try Result<String> {
let file = FileHandle::open(path)?
let content = file.read_all()?
process_content(content)?
} # file 自动关闭
}