7.1 KiB
7.1 KiB
错误处理指南
本文档说明游戏引擎中错误处理的最佳实践和统一模式。
概述
游戏引擎使用统一的错误处理系统,基于thiserror和EngineError类型,提供:
- 类型安全的错误传播
- 错误恢复策略
- 错误监控和统计
- 结构化错误报告
错误类型层次结构
核心错误类型
EngineError
├── Render(RenderError)
├── Physics(PhysicsError)
├── Audio(AudioError)
├── Resource(ResourceError)
├── Input(InputError)
├── System(SystemError)
├── General { message, source, severity, location, backtrace }
├── Multiple { count, errors, primary }
└── Chain { context, source, metadata }
模块级错误类型
每个子系统都有专门的错误类型:
- RenderError: 渲染系统错误(GPU操作、着色器编译、纹理创建等)
- PhysicsError: 物理系统错误(碰撞检测、物理模拟等)
- AudioError: 音频系统错误(音频加载、播放等)
- ResourceError: 资源管理错误(文件加载、资源解析等)
- InputError: 输入系统错误(输入设备、输入映射等)
- SystemError: 系统级错误(内存分配、线程操作等)
错误处理模式
1. 使用Result类型
✅ 正确:
pub fn load_texture(path: &str) -> Result<Texture, RenderError> {
// 可能失败的操作
let data = std::fs::read(path)
.map_err(|e| RenderError::TextureCreation {
texture: path.to_string(),
message: format!("Failed to read file: {}", e),
severity: ErrorSeverity::Error,
})?;
// 处理数据...
Ok(texture)
}
❌ 错误:
pub fn load_texture(path: &str) -> Texture {
let data = std::fs::read(path).unwrap(); // 不要使用unwrap
// ...
}
2. 错误传播
使用?操作符传播错误:
pub fn load_scene(path: &str) -> Result<Scene, EngineError> {
let data = load_file(path)?; // 自动转换为EngineError
let scene = parse_scene(&data)?;
Ok(scene)
}
3. 错误上下文
使用context方法添加上下文信息:
use crate::error::EngineError;
pub fn process_entity(entity_id: u64) -> Result<(), EngineError> {
let entity = find_entity(entity_id)
.ok_or_else(|| EngineError::General {
message: format!("Entity {} not found", entity_id),
source: None,
severity: ErrorSeverity::Error,
location: Some(file!().to_string()),
backtrace: None,
})?;
// 处理实体...
Ok(())
}
4. 错误恢复策略
使用RecoveryStrategy定义错误恢复行为:
use crate::error::{RecoveryStrategy, RecoveryManager};
let recovery_manager = RecoveryManager::new();
recovery_manager.register_strategy(
ErrorCategory::Resource,
RecoveryStrategy::Retry {
max_attempts: 3,
base_delay_ms: 100,
backoff_multiplier: 2.0,
max_delay_ms: 1000,
}
);
错误严重级别
使用ErrorSeverity枚举表示错误的严重程度:
- Info: 信息性消息,不影响系统运行
- Warning: 警告,可能影响性能或用户体验
- Error: 错误,影响部分功能但系统可继续运行
- Critical: 严重错误,影响核心功能
- Fatal: 致命错误,系统无法继续运行
错误监控
使用ErrorMonitor监控错误:
use crate::error::{ErrorMonitor, MonitorConfig};
let monitor = ErrorMonitor::new(MonitorConfig::default());
monitor.record_error(&error);
let stats = monitor.get_stats();
最佳实践
✅ 应该做的
-
使用Result类型返回错误
pub fn operation() -> Result<(), EngineError> -
提供清晰的错误消息
Err(EngineError::General { message: "Failed to load texture: file not found".to_string(), // ... }) -
使用错误恢复策略
let result = retry_executor.execute_with_recovery(|| { load_resource(path) }); -
记录错误上下文
error.with_context("loading scene", "scene.json")
❌ 不应该做的
-
不要使用unwrap()
// ❌ 错误 let value = option.unwrap(); // ✅ 正确 let value = option.ok_or_else(|| EngineError::General { message: "Expected value".to_string(), // ... })?; -
不要忽略错误
// ❌ 错误 let _ = operation(); // ✅ 正确 operation()?; -
不要使用panic
// ❌ 错误 panic!("Something went wrong"); // ✅ 正确 return Err(EngineError::General { message: "Something went wrong".to_string(), severity: ErrorSeverity::Error, // ... });
错误恢复策略
重试策略
use crate::error::retry::{RetryConfig, RetryExecutor};
let config = RetryConfig {
max_attempts: 3,
base_delay: Duration::from_millis(100),
backoff_multiplier: 2.0,
max_delay: Duration::from_secs(1),
};
let executor = RetryExecutor::new(config);
let result = executor.execute(|| {
network_request()
});
使用默认值
use crate::error::RecoveryStrategy;
let strategy = RecoveryStrategy::UseDefault {
default_description: "Using default texture".to_string(),
log_warning: true,
};
优雅降级
let strategy = RecoveryStrategy::GracefulDegradation {
degradation_level: 1,
description: "Reducing texture quality".to_string(),
fallback: "Using lower quality texture".to_string(),
};
错误处理示例
资源加载错误处理
pub async fn load_texture_async(path: &str) -> Result<Texture, EngineError> {
// 尝试加载
match tokio::fs::read(path).await {
Ok(data) => {
Texture::from_bytes(&data)
.map_err(|e| RenderError::TextureCreation {
texture: path.to_string(),
message: format!("Failed to decode texture: {}", e),
severity: ErrorSeverity::Error,
}.into())
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
// 文件不存在,使用默认纹理
tracing::warn!("Texture not found: {}, using default", path);
Ok(Texture::default())
}
Err(e) => {
Err(ResourceError::FileRead {
path: path.to_string(),
message: e.to_string(),
severity: ErrorSeverity::Error,
}.into())
}
}
}
网络错误处理
pub fn send_message(msg: NetworkMessage) -> Result<(), EngineError> {
self.connection.send(msg)
.map_err(|e| SystemError::Network {
message: format!("Failed to send message: {}", e),
severity: ErrorSeverity::Error,
}.into())
}