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
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> |
降级 Rc 、Arc 或任何实现了 [Downgrade] 的东西。捕获降级指针。这有助于打破引用循环。 |
fail(<expr>) <ident> |
与 weak 类似,但在执行闭包体之前升级弱指针。如果升级失败,则跳过执行体并返回表达式。 |
panic<ident> |
与 weak 类似,但在执行闭包体之前升级弱指针。如果升级失败,则以消息 "闭包失败升级弱指针" 播报恐慌。 |
weak
、fail
和 panic
转换
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