This line make Rust errors and I cannot understand what does it mean

I think I found sometimes crazy with Rust.

This code works: Rust Explorer Playground

let domain_player = lambda(PlayerCreateLambdaArgs {
    input,
    shirt_next_value: Box::new(|model: &str| {
        Box::pin(shirt_get_next_and_increase(&mut tx, model))
    }),
})
.await?;

and this not: Rust Explorer Playground

let shirt_next_value =
    Box::new(|model: &str| Box::pin(shirt_get_next_and_increase(&mut tx, model)));

let domain_player = lambda(PlayerCreateLambdaArgs {
    input,
    shirt_next_value,
})
.await?;

and this is the ONLY CHANGE!

What does this even mean?

expected struct `Pin<Box<dyn Future<Output = Result<i64, std::string::String>> + Send>>`
found struct `Pin<Box<impl Future<Output = Result<i64, std::string::String>>>>`

It means that whatever type you pass, it was expected to be Send (i.e., thread safe by-value), but it wasn't.

That part of your code is pretty complicated; it probably tripped up type inference and the compiler simply gave up trying to figure out the correct coercions.

And how can I fix it?

I tried this to aid type inference:

    let shirt_next_value =
        Box::new(|model: &str| -> Pin<Box<dyn Future<Output = Result<i64, String>> + Send>> {
            Box::pin(shirt_get_next_and_increase(&mut tx, model))
        });

But I get:

   Compiling playground v0.1.0 (/home/explorer/playground)
error: captured variable cannot escape `FnMut` closure body
  --> src/main.rs:70:13
   |
66 |     let mut tx = pool.begin().await.unwrap();
   |         ------ variable defined here
...
69 |         Box::new(|model: &str| -> Pin<Box<dyn Future<Output = Result<i64, String>> + Send>> {
   |                                   --------------------------------------------------------- inferred to be a `FnMut` closure
70 |             Box::pin(shirt_get_next_and_increase(&mut tx, model))
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^^
   |             |                                         |
   |             |                                         variable captured here
   |             returns a reference to a captured variable which escapes the closure body
   |
   = note: `FnMut` closures only have access to their captured variables while they are executing...
   = note: ...therefore, they cannot allow references to captured variables to escape

error: lifetime may not live long enough
  --> src/main.rs:70:13
   |
69 |         Box::new(|model: &str| -> Pin<Box<dyn Future<Output = Result<i64, String>> + Send>> {
   |                          -        --------------------------------------------------------- return type of closure is Pin<Box<(dyn Future<Output = Result<i64, std::string::String>> + Send + '1)>>
   |                          |
   |                          let's call the lifetime of this reference `'2`
70 |             Box::pin(shirt_get_next_and_increase(&mut tx, model))
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'2` must outlive `'1`

error: could not compile `playground` due to 2 previous errors

You can try by modifying the code from line 68 on in the original OPs post:

I wonder if some more lifetime annotations are necessary, maybe with for<'lt>, which is experimental yet?

I guess you could use the first version that works, or is there a specific reason you want/need to
write it in the second way?

Because the code is much more complicated in my real project, unfortunately.

I don't really understand the lifetime problem above, but I wondered if it's a similar issue like this one that came up in another thread:

But I might be totally wrong.

I tried to use Box::leak to figure out if I can get the code to compile at least (it would not work, but that might help to find out what's the issue), but unfortunately, I cannot clone the tx or create a new one from within the non-async closure easily.

Hmmm, I see. :face_with_diagonal_mouth:


What I mean is, I believe that the type Pin<Box<dyn Future<Output = Result<i64, String>> + Send>>, which I used in my example, doesn't work because dyn without lifetime means dyn + 'static, I think. But the pinned boxed dyn Future has a lifetime that depends on the transaction and the string slice, and I don't know how to express that.

Wow. Not even you can. It is in these cases that I regret the simplicity of Go and other languages. I love Rust too much to throw it all away and switch back to that, but the temptation is strong.

Why don't you just write the variant that works? Then you don't have to "fix" anything.

Alternatively, aid type inference by simplifying your code and especially the deeply-nested dynamic types.

Because I need the let var = closure.

This is what I'm asking help for... :frowning:

Need to specify type. Inference or type conversion later can't deal with it.
Second error the variable is Drop. Making it use Lexical lifetimes. It captures tx but you use it later. Adding the block expression restricts the life.

    let domain_player = {
        type Snv<'a> = Box<dyn FnOnce(&'a str) -> Pin<Box<dyn Future<Output = Result<i64, String>> + Send + 'a>>
                + Send
                + Sync
                + 'a,
                >;
        let shirt_next_value: Snv =
            Box::new(|model: &str| Box::pin(shirt_get_next_and_increase(&mut tx, model)));
        
        lambda(PlayerCreateLambdaArgs {
            input,
            shirt_next_value,
        })
        .await?
    };
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.