Rust中的设计模式:带示例的实践指南
设计模式是经过验证的典型开发问题解决方案。在Rust中,由于其独特的所有权系统和内存模型,经典模式的实现通常与带有垃圾收集的语言不同。在本文中,我们将分析三个关键模式:Singleton、Builder和Strategy,并根据Rust的特性进行调整。
1. Rust中的Singleton模式:无需unsafe的全局状态
Singleton确保一个类只有一个实例,并提供全局访问点。在Rust中,once_cell crate或稳定的std::sync::OnceLock(自Rust 1.70起)非常适合此目的。
使用OnceLock的实现
use std::sync::OnceLock;
pub struct Logger { level: String,}
impl Logger { pub fn global() -> &'static Logger { static INSTANCE: OnceLock<Logger> = OnceLock::new(); INSTANCE.get_or_init(|| Logger { level: "info".to_string(), }) }
pub fn log(&self, msg: &str) { println!("[{}] {}", self.level, msg); }}
fn main() { let logger = Logger::global(); logger.log("你好,Rust!"); // Logger::global() 将返回同一个实例}优点:安全性(无unsafe)、惰性初始化、线程安全。缺点——全局状态使测试复杂化。
2. Builder模式:构建复杂对象
Builder将复杂对象的构建与其表示分离。在Rust中,它对于具有多个可选字段的结构特别有用。
示例:HTTP客户端配置
pub struct HttpClient { url: String, timeout: u64, headers: Vec<(String, String)>,}
pub struct HttpClientBuilder { url: String, timeout: Option<u64>, headers: Vec<(String, String)>,}
impl HttpClientBuilder { pub fn new(url: &str) -> Self { HttpClientBuilder { url: url.to_string(), timeout: None, headers: vec![], } }
pub fn timeout(mut self, secs: u64) -> Self { self.timeout = Some(secs); self }
pub fn header(mut self, key: &str, value: &str) -> Self { self.headers.push((key.to_string(), value.to_string())); self }
pub fn build(self) -> HttpClient { HttpClient { url: self.url, timeout: self.timeout.unwrap_or(30), headers: self.headers, } }}
fn main() { let client = HttpClientBuilder::new("https://api.example.com") .timeout(10) .header("Authorization", "Bearer token123") .build(); println!("客户端URL: {}", client.url);}重要:在builder的方法中使用self(而不是&self)可以避免克隆并使API更符合人体工程学。
3. Strategy模式:作为可互换策略的算法
Strategy定义了一系列算法,封装每个算法并使它们可以互换。在Rust中,这是通过traits和动态分发(Box<dyn Trait>)实现的。
示例:排序系统
trait SortStrategy { fn sort(&self, data: &mut [i32]);}
struct BubbleSort;impl SortStrategy for BubbleSort { fn sort(&self, data: &mut [i32]) { let n = data.len(); for i in 0..n { for j in 0..n - i - 1 { if data[j] > data[j + 1] { data.swap(j, j + 1); } } } }}
struct QuickSort;impl SortStrategy for QuickSort { fn sort(&self, da