惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
T
Threatpost
P
Palo Alto Networks Blog
NISL@THU
NISL@THU
O
OpenAI News
Project Zero
Project Zero
G
GRAHAM CLULEY
P
Privacy International News Feed
A
Arctic Wolf
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
M
MIT News - Artificial intelligence
T
Threat Research - Cisco Blogs
S
Security @ Cisco Blogs
Google DeepMind News
Google DeepMind News
B
Blog RSS Feed
D
Docker
aimingoo的专栏
aimingoo的专栏
博客园 - 【当耐特】
N
Netflix TechBlog - Medium
云风的 BLOG
云风的 BLOG
雷峰网
雷峰网
W
WeLiveSecurity
P
Proofpoint News Feed
腾讯CDC
Cloudbric
Cloudbric
S
Secure Thoughts
C
Check Point Blog
博客园 - Franky
T
The Exploit Database - CXSecurity.com
T
Troy Hunt's Blog
GbyAI
GbyAI
Security Archives - TechRepublic
Security Archives - TechRepublic
Application and Cybersecurity Blog
Application and Cybersecurity Blog
月光博客
月光博客
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
TaoSecurity Blog
TaoSecurity Blog
L
Lohrmann on Cybersecurity
V
Visual Studio Blog
F
Fortinet All Blogs
博客园 - 叶小钗
C
CXSECURITY Database RSS Feed - CXSecurity.com
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recorded Future
Recorded Future
C
Cisco Blogs
博客园 - 司徒正美
Stack Overflow Blog
Stack Overflow Blog
Y
Y Combinator Blog
Apple Machine Learning Research
Apple Machine Learning Research

Rust Blog

Security Advisory for Cargo (CVE-2026-5223) | Rust Blog Security Advisory for Cargo (CVE-2026-5222) | Rust Blog Project goals update — April 2026 (end of 2025H2) | Rust Blog Rust is participating in Outreachy | Rust Blog Raising the baseline for the `nvptx64-nvidia-cuda` target | Rust Blog Announcing Google Summer of Code 2026 selected projects | Rust Blog Announcing Rust 1.95.0 | Rust Blog docs.rs: building fewer targets by default | Rust Blog Changes to WebAssembly targets and handling undefined symbols | Rust Blog Announcing Rust 1.94.1 | Rust Blog Security advisory for Cargo | Rust Blog What we heard about Rust's challenges | Rust Blog Call for Testing: Build Dir Layout v2 | Rust Blog Announcing rustup 1.29.0 | Rust Blog Announcing Rust 1.94.0 | Rust Blog 2025 State of Rust Survey Results | Rust Blog Rust debugging survey 2026 | Rust Blog Update on the October 15, 2018 incident on crates.io Announcing Rust 1.29.2 Announcing Rust 1.29 Announcing Rust 1.28 What is Rust 2018? Announcing Rust 1.27.2 Announcing Rust 1.27.1 Security Advisory for rustdoc Announcing Rust 1.27 Announcing Rust 1.26.2 Announcing Rust 1.26.1 Rust turns three Announcing Rust 1.26 The Rust Team All Hands in Berlin: a Recap Increasing Rust’s Reach 2018 Announcing Rust 1.25 Rust's 2018 roadmap Announcing Rust 1.24.1 Announcing Rust 1.24 The 2018 Rust Event Lineup Announcing Rust 1.23 New Year's Rust: A Call for Community Blogposts Rust in 2017: what we achieved Announcing Rust 1.22 (and 1.22.1) Fearless Concurrency in Firefox Quantum Announcing Rust 1.21 impl Future for Rust Rust 2017 Survey Results Announcing Rust 1.20 Announcing Rust 1.19 The 2017 Rust Conference Lineup Rust's 2017 roadmap, six months in Increasing Rust’s Reach Announcing Rust 1.18 Two years of Rust The Rust Libz Blitz Launching the 2017 State of Rust Survey Announcing Rust 1.17 Announcing Rust 1.16 Rust's language ergonomics initiative Announcing Rust 1.15.1 Rust's 2017 roadmap Announcing Rust 1.15 Announcing Rust 1.14 Announcing the First Underhanded Rust Contest Announcing Rust 1.13 Announcing Rust 1.12.1 Announcing Rust 1.12 Incremental Compilation Announcing Rust 1.11 Shape of errors to come The 2016 Rust Conference Lineup Announcing Rust 1.10 State of Rust Survey 2016 Announcing Rust 1.9 One year of Rust Taking Rust everywhere with rustup Launching the 2016 State of Rust Survey Cargo: predictable dependency management Introducing MIR Announcing Rust 1.8 Announcing Rust 1.7 Announcing Rust 1.6 Announcing Rust 1.5 Announcing Rust 1.4 Announcing Rust 1.3 Rust in 2016 Announcing Rust 1.2 Rust 1.1 stable, the Community Subteam, and RustCamp Announcing Rust 1.0 Abstraction without overhead: traits in Rust Rust Once, Run Everywhere Mixing matching, mutation, and moves in Rust Fearless Concurrency with Rust Announcing Rust 1.0 Beta Announcing Rust 1.0.0.alpha.2 Rust 1.0: status report and final timeline Announcing Rust 1.0 Alpha Rust 1.0: Scheduling the trains Yehuda Katz and Steve Klabnik are joining the Rust Core Team Cargo: Rust's community crate host Stability as a Deliverable Road to Rust 1.0
Async Closures MVP: Call for Testing! | Inside Rust Blog
Michael Goulet on behalf of The Async Working Group · 2024-08-09 · via Rust Blog

The async working group is excited to announce that RFC 3668 "Async Closures" was recently approved by the Lang team. In this post, we want to briefly motivate why async closures exist, explain their current shortcomings, and most importantly, announce a call for testing them on nightly Rust.

The backstory

Async closures were originally proposed in RFC 2394 which introduced async/await to the language. Simple handling of async closures has existed in nightly since async-await was implemented soon thereafter, but until recently async closures simply desugared into closures that returned async blocks:

let x = async || {};

// ...was just sugar for:
let x = || { async {} };

This had a fundamental limitation that it was impossible to express a closure that returns a future that borrows captured state.

Somewhat relatedly, on the callee side, when users want to take an async closure as an argument, they typically express that as a bound of two different generic types:

fn async_callback<F, Fut>(callback: F)
where
    F: FnOnce() -> Fut,
    Fut: Future<Output = String>;

This also led to an additional limitation that it's impossible to express higher-ranked async fn bounds using this without boxing (since a higher-ranked trait bound on F cannot lead to a higher-ranked type for Fut), leading to unnecessary allocations:

fn async_callback<F>(callback: F)
where
    F: FnOnce(&str) -> Pin<Box<dyn Future<Output = ()> + '_>>;

async fn do_something(name: &str) {}

async_callback(|name| Box::pin(async {
    do_something(name).await;
}));

These limitations were detailed in Niko's blog post on async closures and lending, and later in compiler-errors's blog post on why async closures are the way they are.

OK, so how does RFC 3668 help?

Recent work has focused on reimplementing async closures to be lending and designing a set of async fn traits. While async closures already existed as syntax, this work introduced a new family of async fn traits which are implemented by async closures (and all other callable types which return futures). They can be written like:

fn test<F>(callback: F)
where
    // Either:
    async Fn(Arg, Arg) -> Ret,
    // Or:
    AsyncFn(Arg, Arg) -> Ret,

(It's currently an open question exactly how to spell this bound, so both syntaxes are implemented in parallel.)

RFC 3668 motivates this implementation work in detail, confirming that we need first-class async closures and async fn traits which allow us to express the lending capability of async closures -- read the RFC if you're interested in the whole story!

So how do I help?

We'd love for you to test out these new features! First, on a recently-updated nightly compiler, enable #![feature(async_closure)] (note that, for historical reasons, this feature name is not pluralized).

Async closures are designed to be drop-in compatible (in almost all cases) with closures returning async blocks:

// Instead of writing:
takes_async_callback(|arg| async {
    // Do things here...
});

// Write this:
takes_async_callback(async |arg| {
    // Do things here...
});

And on the callee side, write async fn trait bounds instead of writing "regular" fn trait bounds that return futures:

// Instead of writing:
fn doesnt_exactly_take_an_async_closure<F, Fut>(callback: F)
where
    F: FnOnce() -> Fut,
    Fut: Future<Output = String>
{ todo!() }

// Write this:
fn takes_an_async_closure<F: async FnOnce() -> String>(callback: F) { todo!() }
// Or this:
fn takes_an_async_closure<F: AsyncFnOnce() -> String>(callback: F) { todo!() }

Or if you're emulating a higher-ranked async closure with boxing:

// Instead of writing:
fn higher_ranked<F>(callback: F)
where
    F: Fn(&Arg) -> Pin<Box<dyn Future<Output = ()> + '_>>
{ todo!() }

// Write this:
fn higher_ranked<F: async Fn(&Arg)> { todo!() }
// Or this:
fn higher_ranked<F: AsyncFn(&Arg)> { todo!() }

Shortcomings interacting with the async ecosystem

If you're going to try to rewrite your async projects, there are a few shortcomings to be aware of.

You can't directly name the output future

When you name an async callable bound with the old style, before first-class async fn trait bounds, then as a side-effect of needing to use two type parameters, you can put additional bounds (e.g. + Send or + 'static) on the Future part of the bound, like:

fn async_callback<F, Fut>(callback: F)
where
    F: FnOnce() -> Fut,
    Fut: Future<Output = String> + Send + 'static
{ todo!() }

There isn't currently a way to put similar bounds on the future returned by calling an async closure, so if you need to constrain your callback futures like this, then you won't be able to use async closures just yet.

We expect to support this in the medium/long term via a return-type-notation syntax.

Subtle differences in closure signature inference

Passing an async closure to a generic impl Fn(A, B) -> C bound may not always eagerly infer the closure's arguments to A and B, leading to strange type errors on occasion. For an example of this, see rust-lang/rust#127781.

We expect to improve async closure signature inference as we move forward.

Async closures can't be coerced to fn() pointers

Some libraries take their callbacks as function pointers (fn()) rather than generics. Async closures don't currently implement the same coercion from closure to fn() -> .... Some libraries may mitigate this problem by adapting their API to take generic impl Fn() instead of fn() pointers as an argument.

We don't expect to implement this coercion unless there's a particularly good reason to support it, since this can usually be handled manually by the caller by using an inner function item, or by using an Fn bound instead, for example:

fn needs_fn_pointer<T: Future<Output = ()>>(callback: fn() -> T) { todo!() }

fn main() {
    // Instead of writing:
    needs_fn_pointer(async || { todo!() });
    // Since async closures don't currently support coercion to `fn() -> ...`.

    // You can use an inner async fn item:
    async fn callback() { todo!() }
    needs_fn_pointer(callback);
}

// Or if you don't need to take *exactly* a function pointer,
// you can rewrite `needs_fn_pointer` like:
fn needs_fn_pointer(callback: impl async Fn()) { todo!() }
// Or with `AsyncFn`:
fn needs_fn_pointer(callback: impl AsyncFn()) { todo!() }