4 个版本 (破坏性更新)

0.4.0 2023 年 9 月 8 日
0.3.0 2023 年 9 月 8 日
0.2.0 2023 年 9 月 7 日
0.1.0 2023 年 9 月 6 日

内存管理 中排名 587

MIT/Apache

9KB

closure_attr

此 crate 提供了一个属性,用于简化闭包捕获。

示例

use std::{rc::Rc, cell::Cell, cell::RefCell};

// Expects a 'static callback
fn use_callback<F: FnMut() + 'static>(mut callback: F) {
    callback();
}

#[closure_attr::with_closure] // Enable use of #[closure(...)]
fn example() {
    let s = Rc::new(RefCell::new(String::new()));
    let i = Rc::new(Cell::new(0));

    // The callback captures clones of s and i
    use_callback(
        #[closure(clone s, clone i)]
        move || {
            s.replace(format!("Hello, world! {}", i.get()));
            i.set(i.get() + 1);
        },
    );

    assert_eq!(s.borrow_mut().clone(), "Hello, world! 0");
    assert_eq!(i.get(), 1);
}

example();

它展开为

use_callback({
    let s = s.clone(); // Clone requested by attribute
    let i = i.clone(); // Clone requested by attribute
    move || {
        {... code to force whole captures ...}
        s.replace(format!("Hello, world! {}", i.get()));
        i.set(i.get() + 1);
    }
});

捕获类型

语法 描述
clone<ident> 克隆变量
clonemut <ident> 克隆变量并使其可变
ref <ident> 获取变量的引用
ref mut <ident> 获取变量的可变引用
move <ident> 将变量移动到闭包中
move mut <ident> 将变量移动到闭包中并使其可变
weak<ident> 降级 RcArc 或任何实现了 [Downgrade] 的东西。捕获降级指针。这有助于打破引用循环。
fail(<expr>) <ident> weak 类似,但在执行闭包体之前升级弱指针。如果升级失败,则跳过执行体并返回表达式。
panic<ident> weak 类似,但在执行闭包体之前升级弱指针。如果升级失败,则以消息 "闭包失败升级弱指针" 播报恐慌。

weakfailpanic 转换

use std::{rc::Rc, cell::Cell, cell::RefCell};

#[closure_attr::with_closure]
fn weak_examples() {
    let i = Rc::new(42);

    let weak = #[closure(weak i)]
    move || *i.upgrade().unwrap() + 1; // manual upgrade

    let fail = #[closure(fail(7) i)]
    move || *i + 2;

    let panic = #[closure(panic i)]
    move || *i + 3;

    assert_eq!(weak(), 43);
    assert_eq!(fail(), 44);
    assert_eq!(panic(), 45);
}

weak_examples();

闭包展开为

let weak = {
    let i = ::closure_attr::Downgrade::downgrade(&i);
    move || *i.upgrade().unwrap() + 1 // manual upgrade
};

let fail = {
    let i = ::closure_attr::Downgrade::downgrade(&i);
    move || {
        let Some(i) = ::closure_attr::Upgrade::upgrade(&i) else {
            return 7;
        };
        *i + 2
    }
};

let panic = {
    let i = ::closure_attr::Downgrade::downgrade(&i);
    move || {
        let Some(i) = ::closure_attr::Upgrade::upgrade(&i) else {
            ::std::panic!("Closure failed to upgrade weak pointer");
        };
        *i + 3
    }
};

完整捕获

capture 属性捕获整个变量。例如,没有该属性的这个代码将产生错误

fn send<T: Send>(_: T) {}

struct SendPointer(*const ());
unsafe impl Send for SendPointer {}

fn f() {
    let p = SendPointer(std::ptr::null());
    send(
        move || {
            p.0;
        },
    );
}
error[E0277]: `*const ()` cannot be sent between threads safely

一个解决方案

#[closure_attr::with_closure]
fn f() {
    let p = SendPointer(std::ptr::null());
    send(
        #[closure(move p)]
        move || {
            p.0;
        },
    );
}

这相当于在闭包体中插入 let _ = &p;

许可证

此作品在 MIT 和 Apache 2.0 许可证下双重许可。如果您使用此作品,可以选择其中之一。

SPDX-许可证-标识符: MIT Apache-2.0

依赖项

~285–740KB
~18K SLoC