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

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!"));
}

Related

How to allow immutable and mutable borrows to coexist in a function with explicit lifetimes?

For context: I'm implementing an Entity, basically a thin wrapper around a heterogenous map, and trying to implement an update method:
struct Entity {
pub id: u64,
data: HashMap<TypeId, Box<dyn Any>>,
}
impl Entity {
pub fn new(id: u64) -> Self {
Entity { id, data: HashMap::new() }
}
pub fn get_atom<T: Any>(&self) -> Option<&T> {
self.data.get(&TypeId::of::<T>())?.downcast_ref()
}
pub fn set_atom<T: Any>(&mut self, value: T) {
self.data.insert(TypeId::of::<T>(), Box::new(value));
}
pub fn update<T: Any, R: Any>(&mut self, f: impl Fn(&T) -> R)
{
if let Some(val) = self.get_atom() {
self.set_atom(f(val));
}
}
}
This works, but gives a warning:
warning: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/entity.rs:71:13
|
70 | if let Some(val) = self.get_atom() {
| --------------- immutable borrow occurs here
71 | self.set_atom(f(val));
| ^^^^^^^^^^^^^^^^---^^
| | |
| | immutable borrow later used here
| mutable borrow occurs here
OK, that's fixable like this, which removes the warning.
pub fn update<T: Any, R: Any>(&mut self, f: impl Fn(&T) -> R)
{
let maybe : Option<R> = self.get_atom().map(f);
if let Some(val) = maybe {
self.set_atom(val);
}
}
The problem I have is when I introduce a trait for abstracting over getting stuff out of the entity (which permits me to abstract over arity: getting a tuple returns a value if each of the components is in the entity):
trait GetComponent<'a, T> {
fn get_component(entity: &'a Entity) -> Option<T>;
}
// sample atom impl
impl <'a> GetComponent<'a, &'a u32> for &'a u32 {
fn get_component(entity: &'a Entity) -> Option<&'a u32> {
entity.get_atom()
}
}
// sample composite impl
impl <'a, A, B> GetComponent<'a, (A, B)> for (A, B) where
A: GetComponent<'a, A>,
B: GetComponent<'a, B>,
{
fn get_component(entity: &'a Entity) -> Option<(A, B)> {
Some((A::get_component(entity)?, B::get_component(entity)?))
}
}
impl Entity {
<in addition to the above>
pub fn get<'a, T: GetComponent<'a, T>>(&'a self) -> Option<T> {
T::get_component(self)
}
pub fn update<'a, T: 'a, R: Any>(&'a mut self, f: impl Fn(&T) -> R)
where &'a T: GetComponent<'a, &'a T>
{
let maybe : Option<R> = self.get().map(f);
if let Some(val) = maybe {
self.set_atom(val);
}
}
}
The trait requires me to be explicit about lifetimes, and everything else I've tried to do so far with the entity seems to be just fine. But this update method gives this compile error (not a warning this time):
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/entity.rs:56:13
|
51 | pub fn update<'a, T: 'a, R: Any>(&'a mut self, f: impl Fn(&T) -> R)
| -- lifetime `'a` defined here
...
54 | let maybe : Option<R> = self.get().map(f);
| ----------
| |
| immutable borrow occurs here
| argument requires that `*self` is borrowed for `'a`
55 | if let Some(val) = maybe {
56 | self.set_atom(val);
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
Now, as far as I can see, there's no reason why I shouldn't be able to immutably borrow for a shorter period, so the immutable borrow "expires" before I do the mutation - just like in the version without explicit lifetimes used prior to the trait.
But I can't for the life of me work out how to make this work.
You can solve this with a higher-rank trait bound (HRTB):
pub fn update<T, R: Any>(&mut self, f: impl Fn(&T) -> R)
where for <'a> &'a T: GetComponent<'a, &'a T>
This says that for any possible lifetime 'a, T must satisfy the given bound. This allows you to specify how the various lifetimes on the type T relate to each other without binding them to a specific lifetime, such as that of &mut self.
(Playground)

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

What happens when a Rust struct contains a lifetimed trait?

Ok, so I'm a total Rust newbie, and I'm experimenting with Rocket. That web framework passes a Form<MyStruct>, and I want to transfer that MyStruct into my own custom struct.
struct Consumer<T> {
d: T,
}
impl<T> Consumer<T> {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner() }
}
}
That doesn't work of course, I get:
the trait `rocket::request::FromForm<'_>` is not implemented for `T`
Next attempt:
impl<T> Consumer<T> where T: FromForm {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner }
}
}
Uh oh:
impl<T> Consumer<T> where T: FromForm {
^^^^^^^^ expected lifetime parameter
So now I find myself completely unable to fix this! The best I can come up with is:
impl<'f, T> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<T>) -> Self {
Consumer { d: form.into_inner }
}
}
But that results in this error:
51 | fn new(form: Form<T>) -> Self {
| _________^
52 | | Consumer { d: form.into_inner }
53 | | }
| |_________^ lifetime mismatch
= note: expected type `rocket::request::FromForm<'_>`
found type `rocket::request::FromForm<'f>`
Verifiable example: https://hastebin.com/eqihaqodux.makefile
Form also has a lifetime parameter. If you tie it to the lifetime of FromForm, then you'll move forward a little:
impl<'f, T> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<'f, T>) -> Self {
Consumer(form.into_inner())
}
fn get(&self) -> &T {
&self.0
}
}
As a general rule, if you return an object that depends on data in another object, then you'll need to link their lifetimes together like this.
At this point, you'll see another error, which conveniently gives you all the information you need to fix it:
error[E0310]: the parameter type `T` may not live long enough
--> src/main.rs:50:17
|
48 | impl<'f, T> Consumer<T> where T: FromForm<'f> {
| - help: consider adding an explicit lifetime bound `T: 'static`...
49 | fn new(form: Form<'f, T>) -> Self {
50 | Consumer(form.into_inner())
| ^^^^^^^^^^
|
note: ...so that the type `T` will meet its required lifetime bounds
--> src/main.rs:50:17
|
50 | Consumer(form.into_inner())
| ^^^^^^^^^^
The into_inner method on Form requires that it's type parameter T has the 'static lifetime, and the error message suggests adding this constraint.
With these changes, it will compile:
impl<'f, T: 'static> Consumer<T> where T: FromForm<'f> {
fn new(form: Form<'f, T>) -> Self {
Consumer(form.into_inner())
}
fn get(&self) -> &T {
&self.0
}
}

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)

Is it possible for a struct to have a reference to a trait object that has generic methods, without making the struct itself generic?

Is it possible for a struct to have a reference to a trait object that has generic methods, without making the struct itself generic?
trait Foo {
fn generic_method<T>(&self) {}
}
struct MyFoo {}
impl Foo for MyFoo {}
struct Bar<'a> {
my_foo: &'a mut (Foo + 'a),
}
impl<'a> Bar<'a> {
fn new(my_foo: &'a mut Foo) -> Self {
Self { my_foo }
}
}
This code gives me the error:
error[E0038]: the trait `Foo` cannot be made into an object
--> src/main.rs:9:5
|
9 | my_foo: &'a mut (Foo + 'a),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= note: method `generic_method` has generic type parameters
error[E0038]: the trait `Foo` cannot be made into an object
--> src/main.rs:13:5
|
13 | fn new(my_foo: &'a mut Foo) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object
|
= note: method `generic_method` has generic type parameters
It is not possible because all the possible instantiations of generic_method are not known beforehand, so there is no way that the compiler could generate a proper vtable for generic_method.
As you mentioned, you can make the struct generic instead:
struct Bar<'a, T: Foo + 'a> {
my_foo: &'a mut T
}
impl<'a, T: Foo> Bar<'a, T> {
fn new(my_foo: &'a mut T) -> Self {
Self {my_foo}
}
}

Resources