跳到主要内容

装饰器模式

问题

Rust 中如何实现装饰器模式?

答案

Rust 没有类继承,装饰器通过函数组合trait + 包装结构体实现。

方式 1:函数装饰器

use std::time::Instant;

// 原始函数
fn compute(x: i32) -> i32 {
std::thread::sleep(std::time::Duration::from_millis(100));
x * x
}

// 装饰器:添加计时功能
fn with_timing<F, R>(name: &str, f: F) -> R
where
F: FnOnce() -> R,
{
let start = Instant::now();
let result = f();
println!("{}: {:?}", name, start.elapsed());
result
}

// 使用
let result = with_timing("compute", || compute(42));

方式 2:HTTP 中间件(最常见的装饰器应用)

Tower 的 Layer 本质就是装饰器模式:

use tower::{Service, Layer, ServiceBuilder};

// 自定义 Layer:给响应添加请求 ID
#[derive(Clone)]
struct RequestIdLayer;

impl<S> Layer<S> for RequestIdLayer {
type Service = RequestIdService<S>;

fn layer(&self, inner: S) -> Self::Service {
RequestIdService { inner }
}
}

#[derive(Clone)]
struct RequestIdService<S> {
inner: S, // 被装饰的服务
}

// RequestIdService 包装了 inner 服务,在调用前后添加逻辑
// 这就是装饰器模式的本质

方式 3:trait 装饰器

trait Logger {
fn log(&self, msg: &str);
}

struct ConsoleLogger;
impl Logger for ConsoleLogger {
fn log(&self, msg: &str) {
println!("[LOG] {}", msg);
}
}

// 装饰器:添加时间戳
struct TimestampLogger<L: Logger> {
inner: L,
}

impl<L: Logger> Logger for TimestampLogger<L> {
fn log(&self, msg: &str) {
let now = chrono::Utc::now().format("%H:%M:%S");
self.inner.log(&format!("[{}] {}", now, msg));
}
}

// 装饰器可以嵌套
let logger = TimestampLogger {
inner: ConsoleLogger,
};
logger.log("hello"); // [LOG] [14:30:00] hello

常见面试问题

Q1: Rust 的装饰器和 TypeScript/Python 装饰器的区别?

答案

维度RustTypeScript/Python
实现方式函数组合 / trait 包装语言内置 @decorator 语法
类型安全编译时检查运行时
性能可内联,零成本有运行时开销
灵活性需手动组合语法糖更方便

在 Rust Web 生态中,Tower Layer 是装饰器模式最成功的应用。

相关链接