#drop #macro #no-std

no-std drop_cell

实现Drop的另一种方式

1个不稳定版本

0.0.0 2022年12月17日

#97#drop

MIT 协议

11KB
58

drop_cell

Rust中实现Drop的另一种方式。

概述

此库提供了defer!宏,用于将执行推迟到栈帧的末尾。

defer!宏模拟Golang Defer语句

defer!(println!("world"));
println!("hello");
return;
println!("unreachable");

输出

hello
world

借用规则

以下代码无法编译。

    let mut v = vec![1, 2];
    defer!(assert_eq!(v, &[1, 2, 3]));
//                    └─ immutable borrow occurs here ──────────┐
    v.push(3); //
//  └─ mutable borrow occurs here                               │
//
// immutable borrow will be used at the end of the stack frame ─┘

我们想在栈帧的末尾运行assert_eq!(v, &[1, 2, 3]),但它违反了借用规则

为了解决这个问题,我们需要将v传递给defer!

    let v = vec![1, 2];
//      └─ consumes it ─┐
//         ┌────────────┘
    defer!(v => assert_eq!(v, &[1, 2, 3]));        
    v.push(3);

示例

use drop_cell::defer;
use std::io::Write;
use std::sync::mpsc;

fn main() {
    no_arg();
    args();
    bind();
}

fn no_arg() {
    let (tx, rx) = mpsc::channel();
    defer! {
        assert_eq!(rx.recv().unwrap(), "hello");
        assert_eq!(rx.recv().unwrap(), "world");
    };
    tx.send("hello").unwrap();
    tx.send("world").unwrap();
}

fn args() {
    let (v1, v2) = (vec![], vec![]);
    defer! { v1, v2 =>
        assert_eq!(v1, b"hello");
        assert_eq!(v2, b"world");
    }
    write!(v1, "hello").unwrap();
    write!(v2, "world").unwrap();
}

fn bind() {
    let ss = vec![];
    defer! { v @ Some(ss) =>
        let v = v.take().unwrap();
        assert_eq!(v.as_slice(), ["hello", "world"]);
    }
    v.as_mut().unwrap().push("hello");
    v.as_mut().unwrap().push("world");
}

何时使用以及何时不使用

何时使用
  • 当你需要一个Finalizer但又不愿意为此创建一个struct时。
何时不使用
  • 当RAII模式更可取时,例如Lock引用计数
  • 当代码在方法内部编写时,使用defer!可能会使代码复杂化。

无运行时依赖