rust 的 defer 几个使用场景


pub trait Deref {
    type Target: ?Sized;

    // Required method
    fn deref(&self) -> &Self::Target;
}

Defer 这个 trait 有一个关联类型,defer 这个函数返回的是关联类型的引用,而不是取消引用的值,这一点可能会造成误解。

可以这样来理解:给定类型 T, 为 T 实现 Defer 是让编译器可以把 &T 引用为 &Target,对使用者面言,操作包装器跟操作实际被包装的类型一样,简化操作。

使用场景:隐式调用 Target 的字段或者方法

struct Point { x: f32, y: f32 }

fn main() {
    let boxed: Box<Point> = Box::new(Point { x: 5, y: 10 });
    println!("X: {}", boxed.x);
}

boxed 并没有 x 字段,但是能正常编译运行。 这是因为编译器首先会先查看 boxed 是否有 x 字段, 如果没有,则会检测是否实现的 Defer,再看 <T as Defer>::Target 有没有 x 的字段。

所以 boxed.x 实际是 boxed.defer().x,编译器可以让我们省略这个 .defer() 的调用,简化操作,像直接操作 Point 一样。

使用场景:借用操作

fn main() {
    let boxed: Box<i32> = Box::new(5);
    print(&boxed);
}

fn print(input: &i32) {
    println!("Input: {input}");
}

这里编译器会检查 &boxed 是否是类型 &i32,如果不是,也会检查是否实现了 Defer,然后检查 &Target 是否是 &i32

所以 print(&boxed) 实际是 print(boxed.defer()),这个 & 借用操作隐式调用了 defer()

使用场景:* 指针操作符

* 操作是与 & 相互的, * 是取值。

fn main() {
    let boxed: Box<&str> = Box::new("hello world");
    let deref_result: &str = *boxed;
}

需要注意,这个 * 改变的是 Target 的值,如:

fn main() {
    let mut boxed: Box<Vec<i32>> = Box::new(vec![2, 5]);
    *boxed = vec![3, 4];

    // 编译过不去,类型不匹配
    *boxed = Box::new(vec![3, 5]);
}

使用场景: 隐式链式调用

fn main() {
    let boxed = Box::new(Box::new(Box::new("hello world")));
    let v = &boxed;
    println!("{v}");
}

任意类型只要实现了 Defer,都可以被这样链式隐式调用 defer(),编译器做了这些检测,方便我们操作,而不是显示这样 T.defer().defer()...