How to use closure instead of trait? - rust

I want to register Gen::my_g as a callback. The simple way is to implement trait Foo for Gen, but I do not want to implement trait Foo for Gen.
In other words, I want to comment out the code marked as B!!! and uncomment the code marked as A!!!.
This is not my code; I can not modify this:
struct S1;
struct TT;
trait MyRes {}
trait Foo {
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a>;
}
impl<F> Foo for F
where
F: for<'a> Fn(&'a mut S1, &[TT]) -> Box<MyRes + 'a>,
{
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
(*self)(ecx, tt)
}
}
fn f1<F>(name: &str, extension: F)
where
F: Foo + 'static,
{
}
This is my code:
struct Gen {}
impl Gen {
fn register(self) {
// f1("aaa", move |ecx, tt| self.my_g(ecx, tt));//A!!!
f1("aaa", self); //B!!!
}
fn my_g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
unimplemented!();
}
}
impl Foo for Gen {
fn g<'a>(&self, ecx: &'a mut S1, tt: &[TT]) -> Box<MyRes + 'a> {
self.my_g(ecx, tt)
}
}
If I uncomment //A!!!, the compiler tells me something that I do not understand:
error[E0271]: type mismatch resolving `for<'a, 'r> <[closure#src/main.rs:29:19: 29:52 self:_] as std::ops::FnOnce<(&'a mut S1, &'r [TT])>>::Output == std::boxed::Box<MyRes + 'a>`
--> src/main.rs:29:9
|
29 | f1("aaa", move |ecx, tt| self.my_g(ecx, tt)); //A!!!
| ^^ expected bound lifetime parameter, found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#12r
= note: required because of the requirements on the impl of `Foo` for `[closure#src/main.rs:29:19: 29:52 self:_]`
= note: required by `f1`
error[E0281]: type mismatch: `[closure#src/main.rs:29:19: 29:52 self:_]` implements the trait `std::ops::Fn<(&mut S1, &[TT])>`, but the trait `for<'a, 'r> std::ops::Fn<(&'a mut S1, &'r [TT])>` is required
--> src/main.rs:29:9
|
29 | f1("aaa", move |ecx, tt| self.my_g(ecx, tt)); //A!!!
| ^^ --------------------------------- implements `std::ops::Fn<(&mut S1, &[TT])>`
| |
| requires `for<'a, 'r> std::ops::Fn<(&'a mut S1, &'r [TT])>`
| expected concrete lifetime, found bound lifetime parameter
|
= note: required because of the requirements on the impl of `Foo` for `[closure#src/main.rs:29:19: 29:52 self:_]`
= note: required by `f1`

This is a known issue:
Confusing type error due to strange inferred type for a closure argument
The Rust compiler currently cannot infer that a closure is valid for any lifetime (which is what the type of Foo::g requires). It will infer any concrete lifetime, but does not generalize beyond that.

Related

lifetime of function pointer is for<'a, '_> while it should be for<'r>

Sometimes I struggle with lifetimes. I'm still learning and I don't know what's happening here:
use std::future::Future;
use futures::future::{BoxFuture, FutureExt};
struct M{}
struct Client{}
impl Client {
async fn send_and_expect<'a>(
&'a mut self,
m: &M
) -> std::result::Result<(), ()> {
Ok(())
}
pub fn connection_retrier<'a, T>(
f: fn(&'a mut Self, &M) -> T,
f_self: &'a mut Self,
f_m: &'a M,
)-> BoxFuture<'a, std::result::Result<(),()>>
where
T: Future<Output = std::result::Result<(), ()>> + 'a
{
async move {
Client::send_and_expect(f_self, f_m).await
}.boxed()
}
async fn send_with_retry<'a>(&'a mut self) -> std::result::Result<(), ()> {
let m = M{};
Client::connection_retrier(
Client::send_and_expect,
&mut *self, &m).await
}
}
Error:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/lib.rs:31:21
|
11 | ) -> std::result::Result<(), ()> {
| --------------------------- the `Output` of this `async fn`'s found opaque type
...
31 | Client::send_and_expect,
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'r> fn(&mut Client, &'r M) -> impl futures::Future`
found fn pointer `for<'a, '_> fn(&'a mut Client, &M) -> impl futures::Future
Playground
I'm now completely confused about why in for<'r> fn(&mut Client, &'r M) -> impl futures::Future, &mut Client has no lifetime. And what does _ means in for<'a, '_> fn(&'a mut Client, &M) -> impl futures::Future`?
I'm very intersted in learning what's happening here.
Cleaning up the code
In order to see this code from the compiler's perspective, let's change all the lifetime parameters in this example to be explicit and have distinct names, expand the async fn sugar, and then look at how the error changes.
The above example is equivalent to the following after lifetime inference and desugaring.
// name the second lifetime, and expand the async fn sugar.
fn send_and_expect<'a, 'b>(&'a mut self, m: &'b M) -> impl Future<Item=Result<(), ()>> + 'a + 'b
{ ... }
// rename 'a to 'c to avoid ambiguous lifetime names
pub fn connection_retrier<'c, T>(
f: for<'d> fn(&'c mut Self, &'d M) -> T, // name the implicit higher-ranked lifetime here
f_self: &'c mut Self,
f_m: &'c M,
)-> BoxFuture<'c, std::result::Result<(), ()>>
where T: Future<Output = std::result::Result<(), ()>> + 'c
{ ... }
// rename 'a to 'e to avoid ambiguous lifetime names
async fn send_with_retry<'e>(&'e mut self) -> std::result::Result<(), ()> {
After making this change, the error becomes:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/lib.rs:31:21
|
11 | ) -> std::result::Result<(), ()> {
| --------------------------- the `Output` of this `async fn`'s found opaque type
...
31 | Client::send_and_expect,
| ^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'d> fn(&mut Client, &'d M) -> impl futures::Future`
found fn pointer `for<'a, 'b> fn(&'a mut Client, &'b M) -> impl futures::Future`
This should clarify your question about '_: it's just the name the compiler gave the inferred second lifetime parameter of send_and_expect. As for the missing lifetime on &mut Client, you can see that it's still missing here. For reasons I do not completely understand, and in ways that depend on the exact error message given, the compiler will sometimes omit concrete lifetimes when printing the type of references, but make no mistake, the lifetime of that reference is 'c.
Solving the error
Onto the actual problem. The signature of f indicates that connection_retrier is expecting a function which (1) takes a reference of lifetime &'c and (2) a reference of any other lifetime, and (3) returns a Future type which will remain valid as long as 'c does, as specified by your where bound.
When we pass send_and_expect to connection_retrier, in order for the signatures to match the compiler is coercing it to the type for<'d> send_and_expect::<'c, 'd>. But that type doesn't meet condition (3) above! Unlike a regular function, the default behavior of an async function is to capture all input lifetimes in its return type, so the return type of for<'d> send_and_expect::<'c, 'd> is in fact impl Future<Item=Result<(), ()>> + 'c + 'd, as you can tell by looking at send_and_expect's expanded signature.
Since this type borrows from the two lifetimes 'c and 'd, and there is no constraint that 'd: 'c (read: 'd outlives 'c), it may not remain valid for the entirety of the lifetime 'c, if 'd ends first. It is this mismatch that results in the rather cryptic lifetime error you received. There are two ways you can solve this problem, depending on your preferred semantics. You can either:
Remove the higher-ranked bound from f entirely, and specify exactly the lifetimes you will be calling it with in connection_retrier (both &'c.)
pub fn connection_retrier<'c, T>(
f: fn(&'c mut Self, &'c M) -> T
f_self: &'c mut Self,
f_m: &'c M,
) -> BoxFuture<'c, std::result::Result<(), ()>>
where T: Future<Output = std::result::Result<(), ()>> + 'c
{ ... }
Keep the signature of connection_retrier the same and specify that the future returned by send_and_expect only borrows from its first argument. To do this, you will need to drop the async fn sugar on the signature and wrap the body in an async move block.
fn send_and_expect<'a, 'b>(&'a mut self, m: &'b M) -> impl Future<Output=Result<(), ()>> + 'a
{ async move { ... } }
Note that you cannot solve this by writing the type of f as for<'d: 'c> fn(&'c mut Self, &'d M) -> T, as bounds are currently not permitted for universally quantified lifetimes.

How to specify that a lifetime from an impl should be the same as the lifetime of 'self'?

I'm starting from a root Fmt and descending recursively (along a Vec<String>) into Fmts produced by a get_subfmt call. When the vector is empty, I call a method (not shown here for brevity). Each preceding Fmt (and its BoxOrRef) has naturally greater lifetime enforced by the recursive function's scope than the following one. This seems safe, but I'm very new to the lifetimes business, so I may have erred in my reasoning somewhere.
Consider the following bit of simplified code:
use std::borrow::Borrow;
pub trait Fmt {
fn get_subfmt<'a>(&'a self, name: &str) -> Option<BoxOrRef<'a, dyn Fmt>>;
}
pub enum BoxOrRef<'a, T: ?Sized + 'a> {
Boxed(Box<T>),
Ref(&'a T)
}
impl<'b, T: Borrow<dyn Fmt + 'b>> Fmt for T {
fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
self.borrow().get_subfmt(name)
}
}
This fails with the following errors:
error[E0308]: method not compatible with trait
--> src/lib.rs:13:5
|
13 | fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `fn(&'a T, &str) -> std::option::Option<BoxOrRef<'a, Fmt + 'a>>`
found type `fn(&'b T, &str) -> std::option::Option<BoxOrRef<'b, Fmt + 'b>>`
note: the lifetime 'a as defined on the method body at 13:5...
--> src/lib.rs:13:5
|
13 | fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 12:1
--> src/lib.rs:12:1
|
12 | impl<'b, T: Borrow<dyn Fmt + 'b>> Fmt for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: method not compatible with trait
--> src/lib.rs:13:5
|
13 | fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected type `fn(&'a T, &str) -> std::option::Option<BoxOrRef<'a, Fmt + 'a>>`
found type `fn(&'b T, &str) -> std::option::Option<BoxOrRef<'b, Fmt + 'b>>`
note: the lifetime 'b as defined on the impl at 12:1...
--> src/lib.rs:12:1
|
12 | impl<'b, T: Borrow<dyn Fmt + 'b>> Fmt for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime 'a as defined on the method body at 13:5
--> src/lib.rs:13:5
|
13 | fn get_subfmt(&'b self, name: &str) -> Option<BoxOrRef<'b, dyn Fmt>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It seems that the compiler can't prove that the 'a from the definition of get_subfmt is the same as 'b from the impl, most likely because I haven't told it that it is. How do I communicate to the compiler that I want the self reference to last precisely 'b? I can't slap a <'a: 'b> on the get_subfmt in the impl, as that doesn't match the method signature. I've tried constraining T to be T: Borrow<dyn Fmt + 'b> + 'b, but that doesn't help, the errors remain.
I could move 'a from the method to the Fmt itself, but it doesn't really seem right, so I would like to avoid it if there's a way to.
This is the best I could come up with:
use std::borrow::Borrow;
pub trait Fmt<'b> {
fn get_subfmt<'a>(&'a self, name: &str) -> Option<BoxOrRef<'a, dyn Fmt + 'a>>
where
'b: 'a;
}
pub enum BoxOrRef<'a, T: ?Sized + 'a> {
Boxed(Box<T>),
Ref(&'a T)
}
impl<'b, T: Borrow<dyn Fmt<'b> + 'b>> Fmt<'b> for T {
fn get_subfmt<'a>(&'a self, name: &str) -> Option<BoxOrRef<'a, dyn Fmt + 'a>>
where
'b: 'a,
{
self.borrow().get_subfmt(name)
}
}
We want the bound 'b: 'a ('b outlives 'a), not 'a: 'b, because a borrowed reference cannot outlive its referent.

A smart constructor for an iterator with a reference to a closure inside

Consider the following code for a (greatly simplified) iterator with a reference to a closure inside:
struct IteratorState<'a, T: 'a + Fn(i32) -> i32> {
closure: &'a T,
}
impl<'a, T: 'a + Fn(i32) -> i32> Iterator for IteratorState<'a, T> {
type Item = i32;
fn next(&mut self) -> Option<i32> {
None
}
}
It compiles and I can construct IteratorStates directly. However, I also need a smart constructor to hide some details of the implementation (not shown in the MCVE). The following attempt does not compile:
fn mk_iter<'a, T: Fn(i32) -> i32>(closure: &'a T) -> impl Iterator<Item = i32> {
IteratorState { closure }
}
The error is
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/lib.rs:14:5
|
14 | IteratorState { closure }
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 13:1...
--> src/lib.rs:13:1
|
13 | fn mk_iter<'a, T: Fn(i32) -> i32>(closure: &'a T) -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:14:21
|
14 | IteratorState { closure }
| ^^^^^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that return value is valid for the call
--> src/lib.rs:13:54
|
13 | fn mk_iter<'a, T: Fn(i32) -> i32>(closure: &'a T) -> impl Iterator<Item = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
I think I understand what the problem is: there's no guarantee that constructed IteratorState won't outlive the contained reference (please correct me if I got this wrong), but I'm not quite sure how to fix it.
The impl Trait syntax supports adding lifetimes to the return type:
fn mk_iter<'a, T: Fn(i32) -> i32>(closure: &'a T) -> impl Iterator<Item = i32> + 'a {
// here ^^^^
IteratorState {
closure
}
}
(link to playground)

Cannot infer a lifetime for a struct containing a reference to a closure [duplicate]

This question already has answers here:
Lifetime annotation for closure argument
(2 answers)
How to declare a higher-ranked lifetime for a closure argument?
(3 answers)
Closed 5 years ago.
I am trying to make this simplified and self-contained version of my code compile:
struct FragMsgReceiver<'a, 'b: 'a> {
recv_dgram: &'a mut FnMut(&mut [u8]) -> Result<&'b mut [u8], ()>,
}
impl<'a, 'b> FragMsgReceiver<'a, 'b> {
fn new(
recv_dgram: &'a mut FnMut(&mut [u8])
-> Result<&'b mut [u8], ()>
) -> Self {
FragMsgReceiver { recv_dgram }
}
}
fn main() {
let recv_dgram = |buff: &mut [u8]| Ok(buff);
let fmr = FragMsgReceiver::new(&mut recv_dgram);
}
Here is the error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:15:43
|
15 | let recv_dgram = |buff: &mut [u8]| Ok(buff);
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:22...
--> src/main.rs:15:22
|
15 | let recv_dgram = |buff: &mut [u8]| Ok(buff);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that expression is assignable (expected &mut [u8], found &mut [u8])
--> src/main.rs:15:43
|
15 | let recv_dgram = |buff: &mut [u8]| Ok(buff);
| ^^^^
note: but, the lifetime must be valid for the block suffix following statement 1 at 16:53...
--> src/main.rs:16:53
|
16 | let fmr = FragMsgReceiver::new(&mut recv_dgram);
| _____________________________________________________^
17 | | }
| |_^
note: ...so that variable is valid at time of its declaration
--> src/main.rs:16:9
|
16 | let fmr = FragMsgReceiver::new(&mut recv_dgram);
| ^^^
From what I understand from the error message, the compiler doesn't understand that the buff reference (argument of recv_dgram) can actually live longer than the inner body of recv_dgram. I could be wrong though.
To give some context, I'm trying to create a struct that wraps a Rust Tokio UDP socket. To do this, I take a reference to a function recv_dgram. In my original code this function takes a buffer as argument, and returns a Future. When the Future is ready, the buffer will be filled. The Future's item also contains the address of sender and the amount of bytes that were written into the buffer.
Let's start by restoring elided lifetime in your declaration
struct FragMsgReceiver<'a, 'b: 'a> {
recv_dgram: &'a mut for<'c> FnMut(&'c mut [u8]) -> Result<&'b mut [u8], ()>,
}
This declaration means that FragMsgReceiver holds a mutable reference to a FnMut trait object which takes a mutable reference to a slice having any lifetime 'c and returns a reference with lifetime 'b: 'a.
This is not what you need. You need an FnMut which returns a reference with the same lifetime as the lifetime of the input parameter. This can be written as:
type FnTraitObject = FnMut(&mut [u8]) -> Result<&mut [u8], ()>;
struct FragMsgReceiver<'a> {
recv_dgram: &'a mut FnTraitObject,
}
impl<'a> FragMsgReceiver<'a> {
fn new(recv_dgram: &'a mut FnTraitObject) -> Self {
FragMsgReceiver { recv_dgram }
}
}
Lifetime elision does the right thing here, but the compiler still complains: "expected bound lifetime parameter, found concrete lifetime", pointing at FragMsgReceiver::new(&mut recv_dgram).
This error is caused by a limitation of Rust's type inference. We need to assist the inference by coercing the type of the closure as it was pointed out by DK.
fn constrain_handler<F>(f: F) -> F
where
F: FnMut(&mut [u8]) -> Result<&mut [u8], ()>,
{
f
}
// ...
let mut recv_dgram = constrain_handler(|buff| Ok(buff));
Complete code on the playground
To clarify, for<'c> means that 'c can be any lifetime and the lifetime is determined at a call site. For example, the pointer to the function fn foo(_: &u32) -> &u32 has the type for<'a> fn(&'a u32) -> &'a u32.

Fn as trait concrete lifetime required

I want to use an API that I can modify reg:
struct Ctx;
trait Foo {}
trait Ex {
fn do_<'a>(&self, cx: &'a mut Ctx) -> Box<Foo + 'a>;
}
impl<F> Ex for F
where
F: for<'a> Fn(&'a mut Ctx) -> Box<Foo + 'a>,
{
fn do_<'a>(&self, ecx: &'a mut Ctx) -> Box<Foo + 'a> {
(*self)(ecx)
}
}
fn reg<F>(name: &str, ext: F)
where
F: Ex + 'static,
{
}
//My code starts here
struct Boo;
impl Boo {
fn f1<'a>(&self, cx: &'a mut Ctx) -> Box<Foo + 'a> {
unimplemented!();
}
}
fn main() {
let boo = Boo;
reg("aaa", move |cx| boo.f1(cx));
}
But I got an error:
error[E0271]: type mismatch resolving `for<'a> <[closure#src/main.rs:33:16: 33:36 boo:_] as std::ops::FnOnce<(&'a mut Ctx,)>>::Output == std::boxed::Box<Foo + 'a>`
--> src/main.rs:33:5
|
33 | reg("aaa", move |cx| boo.f1(cx));
| ^^^ expected bound lifetime parameter 'a, found concrete lifetime
|
= note: concrete lifetime that was found is lifetime '_#9r
= note: required because of the requirements on the impl of `Ex` for `[closure#src/main.rs:33:16: 33:36 boo:_]`
= note: required by `reg`
error[E0281]: type mismatch: `[closure#src/main.rs:33:16: 33:36 boo:_]` implements the trait `std::ops::Fn<(&mut Ctx,)>`, but the trait `for<'a> std::ops::Fn<(&'a mut Ctx,)>` is required
--> src/main.rs:33:5
|
33 | reg("aaa", move |cx| boo.f1(cx));
| ^^^ -------------------- implements `std::ops::Fn<(&mut Ctx,)>`
| |
| requires `for<'a> std::ops::Fn<(&'a mut Ctx,)>`
| expected concrete lifetime, found bound lifetime parameter 'a
|
= note: required because of the requirements on the impl of `Ex` for `[closure#src/main.rs:33:16: 33:36 boo:_]`
= note: required by `reg`
How can I fix this?
In real code my struct Boo contains some data,
and want to call reg for it twice, so I not implement trait Ex, but
try to use closure.
Looks like issue #38714.
While it is being fixed, you can directly implement Ex for Boo.
impl Ex for Boo {
fn do_<'a>(&self, ecx: &'a mut Ctx) -> Box<Foo + 'a> {
self.f1(ecx)
}
}
fn main() {
let boo = Boo;
reg("aaa", boo);
}
In real code my struct Boo contains some data, and want to call reg for it twice, so I not implement trait Ex, but try to use closure.
You'll not be able to do that with the code you provided. move |cx| boo.f1(cx) moves boo into the closure, and you can't use boo after that.
If you want to share data, you'll need to use Rc in Boo.

Resources