return FALSE; $r = well_tag_thread__update(array('id' => $id), $update); return $r; } function well_tag_thread_find($tagid, $page, $pagesize) { $arr = well_tag_thread__find(array('tagid' => $tagid), array('id' => -1), $page, $pagesize); return $arr; } function well_tag_thread_find_by_tid($tid, $page, $pagesize) { $arr = well_tag_thread__find(array('tid' => $tid), array(), $page, $pagesize); return $arr; } ?>rust - How to capture variables in an async closure returned from a function? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rust - How to capture variables in an async closure returned from a function? - Stack Overflow

programmeradmin1浏览0评论

Using the pattern of returning a pinned boxed future from a function, you are able to clone a value being captured.

Playground

use std::pin::Pin;

pub struct Request {}

pub trait HandlerFunc: Send + Sync + Fn(Request) -> Pin<Box<dyn Future<Output = ()> + Send>> {}

impl<F> HandlerFunc for F
where
  F: Send + Sync + Fn(Request) -> Pin<Box<dyn Future<Output = ()> + Send>>,
{}

fn create_handler(v: String) -> impl HandlerFunc {
  move |_req: Request| {
    let v = v.clone(); // ⬅️ closure takes ownership of variable 
                       //    and explicitly clones it every time 
                       //    the closure is called.
    Box::pin(async move {
      println!("{}", v);
      ()
    })
  }
}

#[tokio::main]
async fn main() {
  let cb = create_handler("Hello World".to_string());
  cb(Request{}).await;
  cb(Request{}).await;
}

It would be great to tidy this up using async closures (introduced in 1.85).

fn handler(v: String) -> impl HandlerFunc {
  async move |_req: Request| {
    println!("{}", v)
  }
}

However, when attempting to do this with an async closure, I am unable to clone the incoming value or implicitly rely on Copy to clone the reference.

Playground

pub struct Request {}

pub trait HandlerFunc:
    Sized + Send + Sync + Copy + 'static + Fn(Request) -> Self::OutputFuture
{
    type OutputFuture: Future<Output = ()>;
}

impl<F, Fut: Future<Output = ()>> HandlerFunc for F
where
    F: Sized + Send + Sync + Copy + 'static + Fn(Request) -> Fut,
{
    type OutputFuture = Fut;
}

fn handler(v: i32) -> impl HandlerFunc {
  // ⬇️ error: async closure does not implement `Fn` because
  //           it captures state from its environment
  async move |_req: Request| {
    println!("{}", v) // i32 implements Copy so it should be cloned
                      // I have also tried &v and removing "move"
  }
}

#[tokio::main]
async fn main() {
    let cb = handler(42);
    cb(Request {}).await;
    cb(Request {}).await;
}

Is it possible to implement this using async closures?

Using the pattern of returning a pinned boxed future from a function, you are able to clone a value being captured.

Playground

use std::pin::Pin;

pub struct Request {}

pub trait HandlerFunc: Send + Sync + Fn(Request) -> Pin<Box<dyn Future<Output = ()> + Send>> {}

impl<F> HandlerFunc for F
where
  F: Send + Sync + Fn(Request) -> Pin<Box<dyn Future<Output = ()> + Send>>,
{}

fn create_handler(v: String) -> impl HandlerFunc {
  move |_req: Request| {
    let v = v.clone(); // ⬅️ closure takes ownership of variable 
                       //    and explicitly clones it every time 
                       //    the closure is called.
    Box::pin(async move {
      println!("{}", v);
      ()
    })
  }
}

#[tokio::main]
async fn main() {
  let cb = create_handler("Hello World".to_string());
  cb(Request{}).await;
  cb(Request{}).await;
}

It would be great to tidy this up using async closures (introduced in 1.85).

fn handler(v: String) -> impl HandlerFunc {
  async move |_req: Request| {
    println!("{}", v)
  }
}

However, when attempting to do this with an async closure, I am unable to clone the incoming value or implicitly rely on Copy to clone the reference.

Playground

pub struct Request {}

pub trait HandlerFunc:
    Sized + Send + Sync + Copy + 'static + Fn(Request) -> Self::OutputFuture
{
    type OutputFuture: Future<Output = ()>;
}

impl<F, Fut: Future<Output = ()>> HandlerFunc for F
where
    F: Sized + Send + Sync + Copy + 'static + Fn(Request) -> Fut,
{
    type OutputFuture = Fut;
}

fn handler(v: i32) -> impl HandlerFunc {
  // ⬇️ error: async closure does not implement `Fn` because
  //           it captures state from its environment
  async move |_req: Request| {
    println!("{}", v) // i32 implements Copy so it should be cloned
                      // I have also tried &v and removing "move"
  }
}

#[tokio::main]
async fn main() {
    let cb = handler(42);
    cb(Request {}).await;
    cb(Request {}).await;
}

Is it possible to implement this using async closures?

Share Improve this question edited Mar 19 at 23:34 David Alsh asked Mar 19 at 23:08 David AlshDavid Alsh 7,7238 gold badges44 silver badges79 bronze badges 2
  • You may have to use the prior syntax: move |_req: Request| async move { ... } which will work directly with your Copy code – kmdreko Commented Mar 20 at 1:07
  • Is this what you're looking for? – user4815162342 Commented Mar 20 at 13:00
Add a comment  | 

2 Answers 2

Reset to default 1

Async closures don't implement just the Fn* traits (although they sometimes can be treated as such), but also, and more importantly the AsyncFn* traits. See Calling a generic async function with a (mutably) borrowed argument for details.

However, there is no way to refer to the future of those traits (except on nightly), so the answer to your question is unfortunately no.

Most likely you want to use some of the AsyncFn* traits instead of the Fn trait. But if that is not an option, you can achieve equivalent code to the first example by wrapping the async closure with a utility function (wrap below) that clones the async closure every time before calling it: (note that this function can be reused, which should make the code better than the first example if the utility function is used multiple times)

fn wrap<A, Fut>(a: A) -> impl HandlerFunc<OutputFuture=Fut>
where
    Fut: Future<Output=()>,
    A: Clone + Send + Sync + FnOnce(Request) -> Fut,
{
    move |request|a.clone()(request)
}

fn handler(v: i32) -> impl HandlerFunc {
  wrap(async move |_req: Request| {
    println!("{}", v)
  })
}

Here is a full example:

pub struct Request {}

pub trait HandlerFunc:
    Send + Sync + Fn(Request) -> Self::OutputFuture
{
    type OutputFuture: Future<Output = ()>;
}

impl<F, Fut: Future<Output = ()>> HandlerFunc for F
where
    F: Send + Sync + Fn(Request) -> Fut,
{
    type OutputFuture = Fut;
}

fn wrap<A, Fut>(a: A) -> impl HandlerFunc<OutputFuture=Fut>
where
    Fut: Future<Output=()>,
    A: Clone + Send + Sync + FnOnce(Request) -> Fut,
{
    move |request|a.clone()(request)
}

fn handler(v: i32) -> impl HandlerFunc {
  wrap(async move |_req: Request| {
    println!("{}", v)
  })
}

#[tokio::main]
async fn main() {
    let cb = handler(42);
    cb(Request {}).await;
}
发布评论

评论列表(0)

  1. 暂无评论