🎯 empfohlene Sammlungen
Balanced sample collections from various categories for you to explore
Web Rust Fehlerbehandlungsbeispiele
Web Rust Fehlerbehandlungsbeispiele einschließlich Ausnahmefang, Protokollierung und Parametervalidierung
💻 Protokollierung rust
🟢 simple
⭐⭐⭐
Logs in Dateien und Konsole mit verschiedenen Stufen schreiben
⏱️ 20 min
🏷️ rust, web, error handling
Prerequisites:
Basic Rust, chrono crate
// Web Rust Logging Examples
// Log writing to files and console
//
// Add to Cargo.toml:
// [dependencies]
// log = "0.4"
// env_logger = "0.10"
// chrono = "0.4"
use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::Path;
// 1. Simple Logging to File
/// Log message to file
fn log_to_file(path: &str, message: &str) -> std::io::Result<()> {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(path)?;
writeln!(file, "{}", message)?;
Ok(())
}
/// Log with timestamp
fn log_with_timestamp(path: &str, level: &str, message: &str) -> std::io::Result<()> {
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
let log_entry = format!("[{}] {} - {}", timestamp, level, message);
log_to_file(path, &log_entry)
}
// 2. Log Levels
/// Log debug message
fn log_debug(path: &str, message: &str) -> std::io::Result<()> {
log_with_timestamp(path, "DEBUG", message)
}
/// Log info message
fn log_info(path: &str, message: &str) -> std::io::Result<()> {
log_with_timestamp(path, "INFO", message)
}
/// Log warning message
fn log_warning(path: &str, message: &str) -> std::io::Result<()> {
log_with_timestamp(path, "WARNING", message)
}
/// Log error message
fn log_error(path: &str, message: &str) -> std::io::Result<()> {
log_with_timestamp(path, "ERROR", message)
}
// 3. Structured Logging
/// Structured log entry
#[derive(Debug)]
struct LogEntry {
timestamp: String,
level: String,
message: String,
module: Option<String>,
}
impl LogEntry {
fn new(level: &str, message: &str) -> Self {
LogEntry {
timestamp: chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string(),
level: level.to_string(),
message: message.to_string(),
module: None,
}
}
fn with_module(mut self, module: &str) -> Self {
self.module = Some(module.to_string());
self
}
fn format(&self) -> String {
match &self.module {
Some(m) => format!("[{}] [{}] [{}] - {}", self.timestamp, self.level, m, self.message),
None => format!("[{}] [{}] - {}", self.timestamp, self.level, self.message),
}
}
}
/// Write structured log
fn write_structured_log(path: &str, entry: &LogEntry) -> std::io::Result<()> {
log_to_file(path, &entry.format())
}
// 4. Logger with Multiple Outputs
/// Simple logger that writes to multiple destinations
struct MultiLogger {
log_file: String,
console: bool,
}
impl MultiLogger {
fn new(log_file: &str, console: bool) -> Self {
MultiLogger {
log_file: log_file.to_string(),
console,
}
}
fn log(&self, level: &str, message: &str) -> std::io::Result<()> {
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
let log_entry = format!("[{}] {} - {}", timestamp, level, message);
// Write to file
if !self.log_file.is_empty() {
log_to_file(&self.log_file, &log_entry)?;
}
// Write to console
if self.console {
println!("{}", log_entry);
}
Ok(())
}
fn info(&self, message: &str) -> std::io::Result<()> {
self.log("INFO", message)
}
fn warning(&self, message: &str) -> std::io::Result<()> {
self.log("WARNING", message)
}
fn error(&self, message: &str) -> std::io::Result<()> {
self.log("ERROR", message)
}
fn debug(&self, message: &str) -> std::io::Result<()> {
self.log("DEBUG", message)
}
}
// 5. Rotating Log Files
/// Rotating logger
struct RotatingLogger {
base_path: String,
max_size: u64,
current_file: String,
current_size: u64,
}
impl RotatingLogger {
fn new(base_path: &str, max_size: u64) -> Self {
let current_file = format!("{}.log", base_path);
RotatingLogger {
base_path: base_path.to_string(),
max_size,
current_file: current_file.clone(),
current_size: std::fs::metadata(¤t_file).map(|m| m.len()).unwrap_or(0),
}
}
fn log(&mut self, message: &str) -> std::io::Result<()> {
let entry = format!("{}\n", message);
let entry_size = entry.len() as u64;
// Check if rotation needed
if self.current_size + entry_size > self.max_size {
self.rotate()?;
}
// Append to current file
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(&self.current_file)?;
file.write_all(entry.as_bytes())?;
self.current_size += entry_size;
Ok(())
}
fn rotate(&mut self) -> std::io::Result<()> {
// Find next available number
let mut counter = 1;
loop {
let archive_name = format!("{}.{}.log", self.base_path, counter);
if !Path::new(&archive_name).exists() {
std::fs::rename(&self.current_file, &archive_name)?;
break;
}
counter += 1;
}
// Reset current file
self.current_size = 0;
Ok(())
}
}
// 6. Conditional Logging
/// Logger with level filtering
struct LevelLogger {
log_file: String,
min_level: String,
}
impl LevelLogger {
fn new(log_file: &str, min_level: &str) -> Self {
LevelLogger {
log_file: log_file.to_string(),
min_level: min_level.to_string(),
}
}
fn should_log(&self, level: &str) -> bool {
let levels = vec!["DEBUG", "INFO", "WARNING", "ERROR"];
let current = levels.iter().position(|&l| l == level).unwrap_or(0);
let min = levels.iter().position(|&l| l == &self.min_level).unwrap_or(0);
current >= min
}
fn log(&self, level: &str, message: &str) -> std::io::Result<()> {
if self.should_log(level) {
log_with_timestamp(&self.log_file, level, message)?;
}
Ok(())
}
}
// 7. Async Logging (Simplified)
/// Async-style logger using channels
use std::sync::mpsc;
use std::thread;
struct AsyncLogger {
sender: mpsc::Sender<String>,
}
impl AsyncLogger {
fn new(log_file: &str) -> Self {
let (sender, receiver) = mpsc::channel();
let log_file = log_file.to_string();
thread::spawn(move || {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(&log_file)
.unwrap();
for message in receiver {
writeln!(file, "{}", message).unwrap();
}
});
AsyncLogger { sender }
}
fn log(&self, message: &str) -> std::io::Result<()> {
self.sender.send(message.to_string()).map_err(|e| {
std::io::Error::new(std::io::ErrorKind::Other, e)
})?;
Ok(())
}
}
// 8. Performance Logging
/// Performance logger
fn log_performance(path: &str, operation: &str, duration_ms: u128) -> std::io::Result<()> {
let message = format!("Operation '{}' took {}ms", operation, duration_ms);
log_with_timestamp(path, "PERF", &message)
}
/// Measure execution time
fn measure_time<F, T>(f: F) -> T
where
F: FnOnce() -> T,
{
f()
}
/// Measure and log execution time
fn measure_and_log<F, T>(path: &str, operation: &str, f: F) -> T
where
F: FnOnce() -> T,
{
let start = std::time::Instant::now();
let result = f();
let duration = start.elapsed().as_millis();
let _ = log_performance(path, operation, duration);
result
}
// 9. Error Logging
/// Log error with backtrace
fn log_error_with_context(path: &str, error: &str, context: &str) -> std::io::Result<()> {
let message = format!("Error in '{}': {}", context, error);
log_with_timestamp(path, "ERROR", &message)
}
/// Log warning with details
fn log_warning_details(path: &str, message: &str, details: &str) -> std::io::Result<()> {
let log_msg = format!("{} | Details: {}", message, details);
log_with_timestamp(path, "WARNING", &log_msg)
}
// 10. Batch Logging
/// Log multiple messages efficiently
fn log_batch(path: &str, messages: &[&str]) -> std::io::Result<()> {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(path)?;
for message in messages {
let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S");
writeln!(file, "[{}] - {}", timestamp, message)?;
}
Ok(())
}
// Usage Examples
fn main() -> std::io::Result<()> {
println!("=== Web Rust Logging Examples ===\n");
let log_file = "application.log";
// 1. Basic logging
println!("--- 1. Basic Logging ---");
log_to_file(log_file, "Application started")?;
log_with_timestamp(log_file, "INFO", "System initialized")?;
// 2. Log levels
println!("
--- 2. Log Levels ---");
log_debug(log_file, "Debug information")?;
log_info(log_file, "Application running")?;
log_warning(log_file, "High memory usage")?;
log_error(log_file, "Connection failed")?;
// 3. Structured logging
println!("
--- 3. Structured Logging ---");
let entry = LogEntry::new("INFO", "User logged in").with_module("Auth");
write_structured_log(log_file, &entry)?;
// 4. Multi-logger
println!("
--- 4. Multi-Logger ---");
let logger = MultiLogger::new("multi.log", true);
logger.info("Multi-logger initialized")?;
logger.warning("This goes to console and file")?;
logger.error("Error occurred")?;
// 5. Level filtering
println!("
--- 5. Level Filtering ---");
let level_logger = LevelLogger::new("filtered.log", "WARNING");
level_logger.log("DEBUG", "This won't be logged")?;
level_logger.log("WARNING", "This will be logged")?;
level_logger.log("ERROR", "This will be logged")?;
// 6. Performance logging
println!("
--- 6. Performance Logging ---");
let result = measure_and_log(log_file, "test_operation", || {
std::thread::sleep(std::time::Duration::from_millis(100));
42
});
println!("Result: {}", result);
// 7. Error logging
println!("
--- 7. Error Logging ---");
log_error_with_context(log_file, "File not found", "load_config")?;
log_warning_details(log_file, "Slow query", "took 5 seconds")?;
// 8. Batch logging
println!("
--- 8. Batch Logging ---");
let messages = vec![
"Message 1",
"Message 2",
"Message 3",
];
log_batch(log_file, &messages)?;
// 9. Rotating logger
println!("
--- 9. Rotating Logger ---");
let mut rotating_logger = RotatingLogger::new("rotating", 1024);
for i in 0..10 {
rotating_logger.log(&format!("Log entry {}", i))?;
}
println!("
=== All Logging Examples Completed ===");
println!("Check {} for log output", log_file);
Ok(())
}
💻 Parametervalidierung rust
🟢 simple
⭐⭐⭐
Funktionsparameter mit benutzerdefinierten Regeln und Fehlermeldungen validieren
⏱️ 20 min
🏷️ rust, web, error handling
Prerequisites:
Basic Rust
// Web Rust Parameter Validation Examples
// Function parameter validation with custom rules
use std::fmt;
// 1. Validation Error Types
/// Validation error
#[derive(Debug, Clone, PartialEq)]
enum ValidationError {
TooShort(String, usize),
TooLong(String, usize),
InvalidFormat(String),
OutOfRange(String, String),
Required(String),
Custom(String),
}
impl fmt::Display for ValidationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ValidationError::TooShort(field, min) => {
write!(f, "{} must be at least {} characters", field, min)
},
ValidationError::TooLong(field, max) => {
write!(f, "{} must be at most {} characters", field, max)
},
ValidationError::InvalidFormat(field) => {
write!(f, "{} has invalid format", field)
},
ValidationError::OutOfRange(field, range) => {
write!(f, "{} must be in range {}", field, range)
},
ValidationError::Required(field) => {
write!(f, "{} is required", field)
},
ValidationError::Custom(msg) => {
write!(f, "{}", msg)
},
}
}
}
impl std::error::Error for ValidationError {}
// 2. String Validation
/// Validate string length
fn validate_length(value: &str, field: &str, min: usize, max: usize) -> Result<(), ValidationError> {
if value.is_empty() {
return Err(ValidationError::Required(field.to_string()));
}
if value.len() < min {
return Err(ValidationError::TooShort(field.to_string(), min));
}
if value.len() > max {
return Err(ValidationError::TooLong(field.to_string(), max));
}
Ok(())
}
/// Validate email format
fn validate_email(email: &str) -> Result<(), ValidationError> {
if email.is_empty() {
return Err(ValidationError::Required("Email".to_string()));
}
// Basic email validation
if !email.contains('@') || !email.contains('.') {
return Err(ValidationError::InvalidFormat("Email".to_string()));
}
let parts: Vec<&str> = email.split('@').collect();
if parts.len() != 2 {
return Err(ValidationError::InvalidFormat("Email".to_string()));
}
let (local, domain) = (parts[0], parts[1]);
if local.is_empty() || domain.is_empty() || !domain.contains('.') {
return Err(ValidationError::InvalidFormat("Email".to_string()));
}
Ok(())
}
/// Validate URL format
fn validate_url(url: &str) -> Result<(), ValidationError> {
if url.is_empty() {
return Err(ValidationError::Required("URL".to_string()));
}
if !url.starts_with("http://") && !url.starts_with("https://") {
return Err(ValidationError::InvalidFormat("URL".to_string()));
}
Ok(())
}
/// Validate username
fn validate_username(username: &str) -> Result<(), ValidationError> {
validate_length(username, "Username", 3, 20)?;
// Must be alphanumeric with underscores
if !username.chars().all(|c| c.is_alphanumeric() || c == '_') {
return Err(ValidationError::InvalidFormat("Username".to_string()));
}
Ok(())
}
/// Validate password
fn validate_password(password: &str) -> Result<(), ValidationError> {
validate_length(password, "Password", 8, 128)?;
let has_upper = password.chars().any(|c| c.is_uppercase());
let has_lower = password.chars().any(|c| c.is_lowercase());
let has_digit = password.chars().any(|c| c.is_ascii_digit());
if !has_upper {
return Err(ValidationError::Custom(
"Password must contain at least one uppercase letter".to_string()
));
}
if !has_lower {
return Err(ValidationError::Custom(
"Password must contain at least one lowercase letter".to_string()
));
}
if !has_digit {
return Err(ValidationError::Custom(
"Password must contain at least one digit".to_string()
));
}
Ok(())
}
// 3. Numeric Validation
/// Validate number in range
fn validate_range<T: PartialOrd>(value: T, field: &str, min: T, max: T) -> Result<(), ValidationError> {
if value < min || value > max {
return Err(ValidationError::OutOfRange(
field.to_string(),
format!("{:?} to {:?}", min, max)
));
}
Ok(())
}
/// Validate positive number
fn validate_positive<T: PartialOrd + std::fmt::Debug>(value: T, field: &str) -> Result<(), ValidationError> {
if value <= T::from(0).unwrap() {
return Err(ValidationError::Custom(
format!("{:?} must be positive", field)
));
}
Ok(())
}
/// Validate non-negative number
fn validate_non_negative<T: PartialOrd>(value: T, field: &str) -> Result<(), ValidationError> {
if value < T::from(0).unwrap() {
return Err(ValidationError::Custom(
format!("{:?} must be non-negative", field)
));
}
Ok(())
}
// 4. Collection Validation
/// Validate collection not empty
fn validate_not_empty<T>(collection: &[T], field: &str) -> Result<(), ValidationError> {
if collection.is_empty() {
return Err(ValidationError::Custom(
format!("{} must not be empty", field)
));
}
Ok(())
}
/// Validate collection size
fn validate_collection_size<T>(collection: &[T], field: &str, min: usize, max: usize) -> Result<(), ValidationError> {
if collection.len() < min {
return Err(ValidationError::Custom(
format!("{} must have at least {} items", field, min)
));
}
if collection.len() > max {
return Err(ValidationError::Custom(
format!("{} must have at most {} items", field, max)
));
}
Ok(())
}
/// Validate all unique
fn validate_all_unique<T: std::hash::Hash + Eq + std::fmt::Debug>(collection: &[T], field: &str) -> Result<(), ValidationError> {
use std::collections::HashSet;
let unique: HashSet<_> = collection.iter().collect();
if unique.len() != collection.len() {
return Err(ValidationError::Custom(
format!("{} must contain only unique items", field)
));
}
Ok(())
}
// 5. Date/Time Validation
/// Validate age range
fn validate_age(age: u32) -> Result<(), ValidationError> {
if age < 0 {
return Err(ValidationError::Custom("Age cannot be negative".to_string()));
}
if age > 150 {
return Err(ValidationError::Custom("Age cannot exceed 150".to_string()));
}
Ok(())
}
/// Validate year range
fn validate_year(year: i32) -> Result<(), ValidationError> {
validate_range(year, "Year", 1900, 2100)
}
// 6. Custom Validation Rules
/// Validation rule type
type ValidationRule<T> = Box<dyn Fn(&T) -> Result<(), ValidationError>>;
/// Apply multiple validation rules
fn validate_with_rules<T>(value: &T, rules: &[ValidationRule<T>]) -> Result<(), ValidationError> {
for rule in rules {
rule(value)?;
}
Ok(())
}
/// Create length rule
fn length_rule(field: &'static str, min: usize, max: usize) -> ValidationRule<String> {
Box::new(move |value: &String| {
validate_length(value, field, min, max)
})
}
/// Create range rule
fn range_rule<T: PartialOrd + Copy>(field: &'static str, min: T, max: T) -> ValidationRule<T> {
Box::new(move |value: &T| {
validate_range(*value, field, min, max)
})
}
// 7. Composite Validation
/// User data validation
#[derive(Debug)]
struct User {
username: String,
email: String,
age: u32,
}
impl User {
fn validate(&self) -> Result<(), Vec<ValidationError>> {
let mut errors = Vec::new();
if let Err(e) = validate_username(&self.username) {
errors.push(e);
}
if let Err(e) = validate_email(&self.email) {
errors.push(e);
}
if let Err(e) = validate_age(self.age) {
errors.push(e);
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
/// Product validation
#[derive(Debug)]
struct Product {
name: String,
price: f64,
quantity: u32,
}
impl Product {
fn validate(&self) -> Result<(), Vec<ValidationError>> {
let mut errors = Vec::new();
validate_length(&self.name, "Name", 1, 100)
.map_err(|e| errors.push(e)).ok();
validate_range(self.price, "Price", 0.0, 1000000.0)
.map_err(|e| errors.push(e)).ok();
validate_non_negative(self.quantity, "Quantity")
.map_err(|e| errors.push(e)).ok();
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
// 8. Conditional Validation
/// Validate with condition
fn validate_if(condition: bool, validation: Result<(), ValidationError>) -> Result<(), ValidationError> {
if condition {
validation
} else {
Ok(())
}
}
/// Validate required if
fn validate_required_if(value: &str, condition: bool, field: &str) -> Result<(), ValidationError> {
validate_if(condition && value.is_empty(), Err(ValidationError::Required(field.to_string())))
}
// 9. Sanitization
/// Trim and validate
fn validate_trimmed(value: &str, field: &str, min: usize, max: usize) -> Result<(), ValidationError> {
let trimmed = value.trim();
validate_length(trimmed, field, min, max)
}
/// Sanitize email
fn sanitize_email(email: &str) -> String {
email.trim().to_lowercase()
}
// 10. Validation Builder
/// Simple validation builder
struct Validator<'a, T> {
value: &'a T,
errors: Vec<ValidationError>,
}
impl<'a, T> Validator<'a, T> {
fn new(value: &'a T) -> Self {
Validator {
value,
errors: Vec::new(),
}
}
fn add_rule<F>(mut self, rule: F) -> Self
where
F: FnOnce(&T) -> Result<(), ValidationError>,
{
if let Err(e) = rule(self.value) {
self.errors.push(e);
}
self
}
fn validate(self) -> Result<(), Vec<ValidationError>> {
if self.errors.is_empty() {
Ok(())
} else {
Err(self.errors)
}
}
}
// Usage Examples
fn main() {
println!("=== Web Rust Parameter Validation Examples ===\n");
// 1. String validation
println!("--- 1. String Validation ---");
match validate_username("user123") {
Ok(_) => println!("'user123' is valid"),
Err(e) => println!("Error: {}", e),
}
match validate_username("ab") {
Ok(_) => println!("'ab' is valid"),
Err(e) => println!("Error: {}", e),
}
// 2. Email validation
println!("
--- 2. Email Validation ---");
match validate_email("[email protected]") {
Ok(_) => println!("'[email protected]' is valid"),
Err(e) => println!("Error: {}", e),
}
match validate_email("invalid-email") {
Ok(_) => println!("'invalid-email' is valid"),
Err(e) => println!("Error: {}", e),
}
// 3. Password validation
println!("
--- 3. Password Validation ---");
match validate_password("SecurePass123") {
Ok(_) => println!("Password is valid"),
Err(e) => println!("Error: {}", e),
}
match validate_password("weak") {
Ok(_) => println!("Password is valid"),
Err(e) => println!("Error: {}", e),
}
// 4. Numeric validation
println!("
--- 4. Numeric Validation ---");
match validate_range(50, "Age", 0, 120) {
Ok(_) => println!("Age 50 is valid"),
Err(e) => println!("Error: {}", e),
}
match validate_range(150, "Age", 0, 120) {
Ok(_) => println!("Age 150 is valid"),
Err(e) => println!("Error: {}", e),
}
// 5. Collection validation
println!("
--- 5. Collection Validation ---");
let items = vec![1, 2, 3, 4, 5];
match validate_collection_size(&items, "Items", 1, 10) {
Ok(_) => println!("Collection size is valid"),
Err(e) => println!("Error: {}", e),
}
let empty: Vec<i32> = vec![];
match validate_not_empty(&empty, "Items") {
Ok(_) => println!("Collection is valid"),
Err(e) => println!("Error: {}", e),
}
// 6. User validation
println!("
--- 6. User Validation ---");
let user = User {
username: "john_doe".to_string(),
email: "[email protected]".to_string(),
age: 25,
};
match user.validate() {
Ok(_) => println!("User is valid: {:?}", user),
Err(errors) => {
println!("User validation failed:");
for e in errors {
println!(" - {}", e);
}
},
}
// 7. Product validation
println!("
--- 7. Product Validation ---");
let product = Product {
name: "Laptop".to_string(),
price: 999.99,
quantity: 10,
};
match product.validate() {
Ok(_) => println!("Product is valid: {:?}", product),
Err(errors) => {
println!("Product validation failed:");
for e in errors {
println!(" - {}", e);
}
},
}
// 8. Validation builder
println!("
--- 8. Validation Builder ---");
let result = Validator::new(&"test value")
.add_rule(|v| validate_length(v, "Field", 3, 20))
.add_rule(|v| if v.chars().all(|c| c.is_alphanumeric()) {
Ok(())
} else {
Err(ValidationError::InvalidFormat("Field".to_string()))
})
.validate();
match result {
Ok(_) => println!("Builder validation passed"),
Err(errors) => {
println!("Builder validation failed:");
for e in errors {
println!(" - {}", e);
}
},
}
// 9. URL validation
println!("
--- 9. URL Validation ---");
match validate_url("https://example.com") {
Ok(_) => println!("URL is valid"),
Err(e) => println!("Error: {}", e),
}
println!("
=== All Parameter Validation Examples Completed ===");
}
💻 Ausnahmefang rust
🟡 intermediate
⭐⭐⭐
Fehler mit Result, Option und benutzerdefinierten Fehlertypen behandeln
⏱️ 25 min
🏷️ rust, web, error handling
Prerequisites:
Intermediate Rust
// Web Rust Exception Catching Examples
// Error handling with Result, Option, and custom errors
use std::fmt;
use std::io;
// 1. Custom Error Types
/// Custom error type with detailed information
#[derive(Debug)]
enum AppError {
Io(io::Error),
Parse(String),
Validation(String),
NotFound(String),
Permission(String),
}
impl fmt::Display for AppError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AppError::Io(err) => write!(f, "IO error: {}", err),
AppError::Parse(msg) => write!(f, "Parse error: {}", msg),
AppError::Validation(msg) => write!(f, "Validation error: {}", msg),
AppError::NotFound(msg) => write!(f, "Not found: {}", msg),
AppError::Permission(msg) => write!(f, "Permission denied: {}", msg),
}
}
}
impl std::error::Error for AppError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
AppError::Io(err) => Some(err),
_ => None,
}
}
}
impl From<io::Error> for AppError {
fn from(err: io::Error) -> Self {
AppError::Io(err)
}
}
// 2. Result Handling
/// Basic Result handling
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("Division by zero"))
} else {
Ok(a / b)
}
}
/// Result with custom error
fn read_file_content(path: &str) -> Result<String, AppError> {
std::fs::read_to_string(path).map_err(AppError::from)
}
/// Chain multiple Results
fn process_file(path: &str) -> Result<usize, AppError> {
let content = read_file_content(path)?;
let count = content.lines().count();
Ok(count)
}
// 3. Option Handling
/// Safe division returning Option
fn safe_divide(a: f64, b: f64) -> Option<f64> {
if b == 0.0 {
None
} else {
Some(a / b)
}
}
/// Get element from vector
fn get_element<T>(vec: &[T], index: usize) -> Option<&T> {
vec.get(index)
}
/// Parse to integer with Option
fn parse_optional(s: &str) -> Option<i32> {
s.parse().ok()
}
// 4. Error Propagation
/// Function that propagates errors
fn load_config(path: &str) -> Result<String, AppError> {
let content = std::fs::read_to_string(path)?;
Ok(content)
}
/// Function with custom error creation
fn validate_username(name: &str) -> Result<(), AppError> {
if name.is_empty() {
return Err(AppError::Validation("Username cannot be empty".to_string()));
}
if name.len() < 3 {
return Err(AppError::Validation("Username must be at least 3 characters".to_string()));
}
if name.len() > 20 {
return Err(AppError::Validation("Username must be at most 20 characters".to_string()));
}
Ok(())
}
// 5. Multiple Error Types
/// Operation that can fail in multiple ways
fn complex_operation(path: &str) -> Result<String, Box<dyn std::error::Error>> {
let content = std::fs::read_to_string(path)?;
let trimmed = content.trim();
if trimmed.is_empty() {
return Err("File is empty".into());
}
Ok(trimmed.to_string())
}
// 6. Error Recovery
/// Attempt operation with fallback
fn read_with_fallback(path: &str, fallback: &str) -> String {
read_file_content(path).unwrap_or_else(|_| fallback.to_string())
}
/// Try multiple alternatives
fn try_alternatives(paths: &[&str]) -> Result<String, AppError> {
for path in paths {
if let Ok(content) = read_file_content(path) {
return Ok(content);
}
}
Err(AppError::NotFound("No valid path found".to_string()))
}
// 7. Error Context
/// Add context to errors
fn read_file_with_context(path: &str) -> Result<String, AppError> {
std::fs::read_to_string(path)
.map_err(|e| AppError::Io(e))
.and_then(|content| {
if content.is_empty() {
Err(AppError::Parse(format!("File {} is empty", path)))
} else {
Ok(content)
}
})
}
// 8. Panic Handling
/// Function that may panic
fn risky_operation(value: i32) -> i32 {
if value < 0 {
panic!("Negative value not allowed: {}", value);
}
value * 2
}
/// Catch panic using std::panic
fn safe_risky_operation(value: i32) -> Result<i32, String> {
std::panic::catch_unwind(|| risky_operation(value))
.map_err(|_| "Panic occurred".to_string())
}
// 9. Combining Results
/// Combine multiple Results
fn combine_results(results: Vec<Result<i32, String>>) -> Result<Vec<i32>, String> {
results.into_iter().collect()
}
/// Collect first error or all successes
fn collect_first_error<T, E>(results: Vec<Result<T, E>>) -> Result<Vec<T>, E> {
results.into_iter().collect()
}
// 10. Conditional Error Handling
/// Handle error based on type
fn handle_io_error(result: Result<String, io::Error>) -> String {
match result {
Ok(content) => content,
Err(e) if e.kind() == io::ErrorKind::NotFound => "File not found".to_string(),
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => "Permission denied".to_string(),
Err(e) => format!("IO error: {}", e),
}
}
// Usage Examples
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== Web Rust Exception Catching Examples ===\n");
// 1. Basic Result handling
println!("--- 1. Basic Result ---");
match divide(10.0, 2.0) {
Ok(result) => println!("10 / 2 = {}", result),
Err(e) => println!("Error: {}", e),
}
match divide(10.0, 0.0) {
Ok(result) => println!("10 / 0 = {}", result),
Err(e) => println!("Error: {}", e),
}
// 2. Option handling
println!("
--- 2. Option ---");
println!("10 / 2 = {:?}", safe_divide(10.0, 2.0));
println!("10 / 0 = {:?}", safe_divide(10.0, 0.0));
let vec = vec![1, 2, 3];
println!("Element at index 1: {:?}", get_element(&vec, 1));
println!("Element at index 10: {:?}", get_element(&vec, 10));
// 3. Custom errors
println!("
--- 3. Custom Errors ---");
match validate_username("") {
Ok(_) => println!("Username valid"),
Err(e) => println!("Validation error: {}", e),
}
match validate_username("ab") {
Ok(_) => println!("Username valid"),
Err(e) => println!("Validation error: {}", e),
}
match validate_username("valid_user") {
Ok(_) => println!("Username valid"),
Err(e) => println!("Validation error: {}", e),
}
// 4. Error propagation
println!("
--- 4. Error Propagation ---");
match load_config("nonexistent.txt") {
Ok(_) => println!("Config loaded"),
Err(e) => println!("Load error: {}", e),
}
// 5. Multiple error types
println!("
--- 5. Multiple Error Types ---");
match complex_operation("test.txt") {
Ok(content) => println!("Content length: {}", content.len()),
Err(e) => println!("Error: {}", e),
}
// 6. Fallback
println!("
--- 6. Fallback ---");
let result = read_with_fallback("missing.txt", "default content");
println!("With fallback: {}", result);
// 7. Try alternatives
println!("
--- 7. Try Alternatives ---");
let paths = ["file1.txt", "file2.txt", "file3.txt"];
match try_alternatives(&paths) {
Ok(_) => println!("Found a valid file"),
Err(e) => println!("All alternatives failed: {}", e),
}
// 8. Combine results
println!("
--- 8. Combine Results ---");
let results = vec![
Ok(1),
Ok(2),
Err("Error 3".to_string()),
Ok(4),
];
match combine_results(results) {
Ok(values) => println!("All results: {:?}", values),
Err(e) => println!("Failed with: {}", e),
}
// 9. Panic handling
println!("
--- 9. Panic Handling ---");
match safe_risky_operation(10) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Panic caught: {}", e),
}
match safe_risky_operation(-5) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Panic caught: {}", e),
}
// 10. Conditional error handling
println!("
--- 10. Conditional Error Handling ---");
let io_result: Result<String, io::Error> = Err(io::Error::new(io::ErrorKind::NotFound, "Not found"));
println!("IO error: {}", handle_io_error(io_result));
println!("
=== All Exception Catching Examples Completed ===");
Ok(())
}