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

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)

Related

Trait associated type lifetime and self

I have a struct that wraps a std::cell::Ref and provides access by reference to the underlying value. Something like this:
use std::cell::Ref;
struct IntAccess<'a> {
i: Ref<'a, i32>,
}
impl IntAccess<'_> {
fn get(&self) -> &i32 {
&self.i
}
}
This works fine. Since I have multiple structs like this, I'd like to define a common trait:
trait Access {
type Item;
fn get(&self) -> Self::Item;
}
However, I get into trouble when trying to implement Access for IntAccess:
impl<'a> Access for IntAccess<'a> {
type Item = &'a i32;
fn get(&self) -> Self::Item {
&self.i
}
}
It fails with the following error:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:23:9
|
23 | &self.i
| ^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/main.rs:22:12
|
22 | fn get(&self) -> Self::Item {
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:23:9
|
23 | &self.i
| ^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/main.rs:19:6
|
19 | impl<'a> Access for IntAccess<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:22:33
|
22 | fn get(&self) -> Self::Item {
| _________________________________^
23 | | &self.i
24 | | }
| |_____^
= note: expected `<IntAccess<'a> as Access>`
found `<IntAccess<'_> as Access>`
I think I kind of get what the compiler is trying to tell me: I'm trying to borrow self.i which has an anonymous lifetime unrelated to the lifetime of Self::Item ('a). So what seems to be needed is to somehow tie the lifetime of self in get to the lifetime 'a. Is there a way to do this?
I have to admit that I don't fully grasp the problem. Since I pass the lifetime 'a to the Ref, and Ref internally stores a reference with this lifetime, it seems to me that it should somehow be possible to get a reference with lifetime 'a out of it without having to explicitly tie self to this lifetime as well. So what am I missing here?
Your understanding is correct. About your doubt, let's name the lifetimes for easier debugging:
impl<'a> Access for IntAccess<'a> {
type Item = &'a i32;
fn get<'b>(&'b self) -> Self::Item {
&self.i
}
}
self has the type &'b IntAccess<'a>. 'b is shorter than or equal to 'a - that is required for self to be well-formed, i.e. able to exist (otherwise, it would contain a dangling reference).
For that reason, we cannot borrow self for more than 'b - or we could do something like:
let v: IntAccess<'a>;
let inner: &'a i32 = {
let r: &'b IntAccess<'a> = &v;
<IntAccess<'a> as Access>::get(r)
}
let mut_r: &mut IntAccess<'a> = &mut v;
And we have both a shared and a mutable reference to (parts of) inner!
Your problem cannot be solved fully without Generic Associated Types. They allow you to parameterize an associated type by a lifetime, making it able to express "I want to return this associated type tied to the lifetime of self":
#![feature(generic_associated_types)]
trait Access {
type Item<'a>
where
Self: 'a;
fn get<'a>(&'a self) -> Self::Item<'a>;
// Or, with lifetime elision:
// fn get(&self) -> Self::Item<'_>;
}
impl<'a> Access for IntAccess<'a> {
type Item<'b> = &'b i32
where
'a: 'b;
fn get<'b>(&'b self) -> Self::Item<'b> {
&self.i
}
}
Playground.
Can we do that on stable? We can emulate that. Instead of implementing Access for IntAccess itself, we will implement it for a reference to it!
trait Access {
type Item;
fn get(self) -> Self::Item;
}
impl<'a, 'b> Access for &'b IntAccess<'a> {
type Item = &'b i32;
fn get(self) -> &'b i32 {
&self.i
}
}
Playground
This does not always work, and thus is not a full replacement to GATs, but is good enough in this case.

Lifetime collision when bounding reference of a trait as IntoIterator

I tried to implement some graph algorithms on generic graphs. For that, I defined two graph traits which would return either a generic trait (having set-operations) SetGraph or an IntoIterator used to iterate over the nodes NeighborhoodIteratorGraph.
pub trait NeighborhoodIteratorGraph<'a> {
//which into_iterator do we have?
type IntoIter: 'a + std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter;
}
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&'a self, index: usize) -> &'a Self::S;
}
Because one is usually able to iterate over sets, I also implemented NeighborhoodIteratorGraph for all SetGraph which are able to iterate over their sets.
impl<'a, G> NeighborhoodIteratorGraph<'a> for G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator(&'a self, index: usize) -> Self::IntoIter {
self.get_neighborhood(index)
}
}
I needed to add a lifetime to NeighborrhoodIteratorGraph otherwise the compiler would tell me my implementation would have an unbounded lifetime.
However I quicky run into problems with these lifetimes and I get an error for the following code:
struct Foo<'a, G: NeighborhoodIteratorGraph<'a>> {
graph: G,
//otherwise we get an error because 'a wouldn't be used
_marker: std::marker::PhantomData<&'a G>,
}
impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
It seems that the PhantomData field is more a hack and I can't find a way in which I get a set refernce which can be seen as a IntoIterator object.
Here is the Rust Playground of the problem.
Full error message:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 34:5...
--> src/lib.rs:34:5
|
34 | / pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
35 | | where
36 | | I: std::iter::IntoIterator<Item = usize>,
| |_________________________________________________^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:38:21
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 33:6...
--> src/lib.rs:33:6
|
33 | impl<'a, G: NeighborhoodIteratorGraph<'a>> Foo<'a, G> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:38:32
|
38 | for node in self.graph.get_neighborhood_iterator(3) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `&'a G`
found `&G`
What you want is a workaround for the lack of generic associated types, which are currently very unstable. Something Like
pub trait NeighborhoodIteratorGraph {
type IntoIter<'a>: std::iter::IntoIterator<Item = usize> + 'a;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter<'b>;
}
would serve you perfectly if they were stable.
The first thing I did is remove the lifetime bound on NeighborhoodIteratorGraph and add it to the return type:
pub trait NeighborhoodIteratorGraph {
type IntoIter: std::iter::IntoIterator<Item = usize>;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b;
}
I then removed unnecessary lifetime annotations from SetGraph:
pub trait SetGraph<'a>
where
&'a Self::S: IntoIterator<Item = usize>,
Self::S: 'a,
{
type S;
fn get_neighborhood(&self, index: usize) -> &Self::S;
}
I then changed the blanket impl's signature to match the modified traits, and changed the impl from G to &'a G to properly constrain the lifetime 'a:
impl<'a, G> NeighborhoodIteratorGraph for &'a G
where
G: SetGraph<'a>,
&'a G::S: IntoIterator<Item = usize>,
{
type IntoIter = &'a G::S;
fn get_neighborhood_iterator<'b>(&'b self, index: usize) -> Self::IntoIter
where
Self::IntoIter: 'b,
{
self.get_neighborhood(index)
}
}
Because of those changes I was able to simplify Foo and its impl:
struct Foo<G: NeighborhoodIteratorGraph> {
graph: G,
}
impl<G: NeighborhoodIteratorGraph> Foo<G> {
pub fn find_matching_for<I>(&mut self, nodes: I) -> bool
where
I: std::iter::IntoIterator<Item = usize>,
{
for node in self.graph.get_neighborhood_iterator(3) {}
return true;
}
}
Leaving the compiler output with nothing but dead code warnings. Playground link

Problem with lifetimes and implementing Clone

I'm trying to define a struct representing a function that can be composed using different arithmetic operations (only addition has been implemented).
I would like to implement Clone for my struct, however I can't seem to it to work:
use std::ops::Add;
use std::boxed::Box;
use std::clone::Clone;
type InputT = i32;
type OutputT = f64;
pub struct ComposableFn<'a> {
f: Box<dyn 'a + Fn(InputT) -> OutputT>,
}
impl<'a> ComposableFn<'a> {
pub fn new<F: 'a + Fn(InputT) -> OutputT>(f: F) -> Self {
Self {
f: Box::new(f)
}
}
pub fn compute(&self, x: InputT) -> OutputT {
(self.f)(x)
}
}
impl<'a> Add<&'a ComposableFn<'a>> for &'a ComposableFn<'a> {
type Output = ComposableFn<'a>;
fn add(self, rhs: &'a ComposableFn) -> Self::Output {
ComposableFn::new(move |x| self.compute(x) + rhs.compute(x))
}
}
impl<'a> Clone for ComposableFn<'a> {
fn clone(&'a self) -> Self {
ComposableFn::new(move |x| self.compute(x))
}
}
fn main() {
let id = ComposableFn::new(|x| x.into());
println!("{}", id.compute(12));
let double = &id + &id;
println!("{}", double.compute(7));
let triple = &double + &id;
println!("{}", triple.compute(3));
}
When compiling I get the following error:
error[E0308]: method not compatible with trait
--> src/main.rs:33:5
|
33 | fn clone(&'a self) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected fn pointer `fn(&ComposableFn<'a>) -> ComposableFn<'_>`
found fn pointer `fn(&'a ComposableFn<'a>) -> ComposableFn<'_>`
note: the anonymous lifetime #1 defined on the method body at 33:5...
--> src/main.rs:33:5
|
33 | fn clone(&'a self) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the lifetime `'a` as defined on the impl at 32:6
--> src/main.rs:32:6
|
32 | impl<'a> Clone for ComposableFn<'a> {
| ^^
error: aborting due to previous error
Removing the 'a from fn clone(&'a self) results in the following error instead:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:34:27
|
34 | ComposableFn::new(move |x| self.compute(x))
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 33:5...
--> src/main.rs:33:5
|
33 | fn clone(&self) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that the types are compatible
--> src/main.rs:34:27
|
34 | ComposableFn::new(move |x| self.compute(x))
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `&ComposableFn<'_>`
found `&ComposableFn<'a>`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 32:6...
--> src/main.rs:32:6
|
32 | impl<'a> Clone for ComposableFn<'a> {
| ^^
note: ...so that the expression is assignable
--> src/main.rs:34:9
|
34 | ComposableFn::new(move |x| self.compute(x))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected `ComposableFn<'a>`
found `ComposableFn<'_>`
error: aborting due to previous error
Is there a way to fix this?
You cannot implement Clone this way. Clone requires the return type to match exactly, which means the exact same lifetime 'a. But you're trying to make a clone that references self which has a different lifetime.
The straightforward solution would be to just clone f. Unfortunately, you can't clone a Box<dyn...>, at least not without some help. See: How to clone a struct storing a boxed trait object?
The only direct solution would be to swap Box out with Rc so they share ownership:
use std::rc::Rc;
pub struct ComposableFn<'a> {
f: Rc<dyn 'a + Fn(InputT) -> OutputT>,
}
impl Clone for ComposableFn<'_> {
fn clone(&self) -> Self {
ComposableFn { f: self.f.clone() }
}
}

Why is a reference to a type that implements Fn not recognized as a callable?

Even if &T is defined as implementing the Fn trait, the compiler rejects it when invoking it is as a callable:
trait Trait {
fn act(self);
}
//passes
fn test_ref_input_as_trait<'a, T>(t: &'a T)
where
&'a T: Trait,
{
t.act();
}
//fails
fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
where
&'a T: Fn(),
{
t();
}
//passes
fn test_input_as_fntrait<T>(t: T)
where
T: Fn(),
{
t();
}
The compiler rejects the definition of the second function with:
error[E0618]: expected function, found `&'a T`
--> src/lib.rs:18:5
|
14 | fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
| - `&'a T` defined here
...
18 | t();
| ^^^ not a function
With nightly (1.32), the error message is replaced with:
error[E0618]: expected function, found `&'a T`
--> src/lib.rs:18:5
|
14 | fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
| - `&'a T` defined here
...
18 | t();
| ^--
| |
| call expression requires function
Maybe I'm missing something, but why is the compiler accepting the definition but not allowing it to be invoked? Is it a syntactical shortcoming from my side that leads it to understand something else?
There is an open issue (#42736) about this. However, the docs for Fn state:
for any type F that implements Fn, &F implements Fn, too.
This means that the following works:
fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
where
T: Fn(),
{
t();
}
This is perhaps a bug (e.g. it works if you replace the &'a T by (&'a T,)). Nevertheless, you can call the function like this:
fn test_ref_input_as_fntrait<'a, T>(t: &'a T)
where
&'a T: Fn(),
{
(&t)();
}
but since T: Fn() automatically implies &T: Fn(), it is easier and more idiomatic to just write like your last example.
fn test_ref_input_as_fntrait<F: Fn()>(t: F) {
t();
}
fn main() {
test_ref_input_as_fntrait(&|| println!("it's okay!"));
}

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.

Resources