This trait declaration and definition one works correctly without any problem:
trait FTrait<T>: Fn(T, T) -> T {}
impl<T, F> FTrait<T> for F where F: Fn(T, T) -> T, {}
...
fn hof(f: impl FTrait<u32>) -> impl FTrait<u32> { //fourth with a generic trait in use with concrete types
move |a, b| {
let r = f(a, b);
r
}
}
But this trait declaration gives multiple errors:
trait FTraitBorrowed<'a, T>: Fn(&'a T, &'a T) -> &'a T {}
impl<'a, T, F> FTraitBorrowed<'a, T: 'a, F> for F where F: Fn(&'a T, &T) -> &'a T, {}
....
fn hof_borrowed(f: impl FTraitBorrowed<i32>) -> impl FTraitBorrowed<i32 > {
move |a, b| {
let r = f(a, b);
r
}
The errors are listed here:
Errors:
error: associated type bindings must be declared after generic parameters
--> src\main.rs:44:31
|
44 | impl<'a, T, F> FTraitBorrowed<'a, T: 'a, F> for F where F: Fn(&'a T, &T) -> &'a T, {}
| ^^^^-----^^^
| |
| this associated type binding should be moved after the generic parameters
error[E0658]: associated type bounds are unstable
--> src\main.rs:44:35
|
44 | impl<'a, T, F> FTraitBorrowed<'a, T: 'a, F> for F where F: Fn(&'a T, &T) -> &'a T, {}
| ^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/52662
error[E0229]: associated type bindings are not allowed here
--> src\main.rs:44:35
|
44 | impl<'a, T, F> FTraitBorrowed<'a, T: 'a, F> for F where F: Fn(&'a T, &T) -> &'a T, {}
| ^^^^^ associated type not allowed here
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0229, E0658.
For more information about an error, try `rustc --explain E0229`.
Could not clearly understand what are wrong from the hints.
For the first error goes away, if I interchange the positions of F and T like this in the implementation:
impl<'a, T, F> FTraitBorrowed<'a, F, T: 'a, > ...
Could someone please help?
Thanks.
The issue that causes the errors is that type bounds aren't allowed there:
// correct
impl<'a, T: 'a, F> FTraitBorrowed<'a, T, F> ...
// wrong
impl<'a, T, F> FTraitBorrowed<'a, T: 'a, F> ...
Because of this, Rust thought that you're using the unstable feature associated type bounds, which caused the confusing error messages.
There were also some other issues, which I managed to fix (playground):
trait FTraitBorrowed<'a, T: 'a>: Fn(&'a T, &'a T) -> &'a T {}
impl<'a, T: 'a, F> FTraitBorrowed<'a, T> for F where F: Fn(&'a T, &'a T) -> &'a T {}
fn hof_borrowed<'a, F>(f: impl FTraitBorrowed<'a, i32>) -> impl FTraitBorrowed<'a, i32> {
move |a, b| f(a, b)
}
Related
I cannot use a concrete type for my struct generic parameter:
struct Foo<'a, T: 'a, K: 'a, F>
where
for<'r> F: Fn(&'r T) -> K,
{
t: &'a T,
k: K,
f: F,
}
impl<'a, T: 'a> Foo<'a, T, &'a T, for<'r> fn(&'r T) -> &'r T> {
//
}
I think I must add more information the the hrtb generic function, but I cannot figure out what:
error[E0308]: mismatched types
--> src/lib.rs:10:17
|
10 | impl<'a, T: 'a> Foo<'a, T, &'a T, for<'r> fn(&'r T) -> &'r T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
|
= note: expected associated type `<for<'r> fn(&'r T) -> &'r T as FnOnce<(&T,)>>::Output`
found associated type `<for<'r> fn(&'r T) -> &'r T as FnOnce<(&'r T,)>>::Output`
note: the required lifetime does not necessarily outlive the lifetime `'a` as defined here
--> src/lib.rs:10:6
|
10 | impl<'a, T: 'a> Foo<'a, T, &'a T, for<'r> fn(&'r T) -> &'r T> {
| ^^
note: the lifetime requirement is introduced here
--> src/lib.rs:3:29
|
3 | for<'r> F: Fn(&'r T) -> K,
| ^
What is frustrating is that if my function returns a reference, it works correctly:
struct Foo<'a, T: 'a, K: 'a, F>
where
for<'r> F: Fn(&'r T) -> &'r K,
{
t: &'a T,
k: K,
f: F,
}
impl<'a, T: 'a> Foo<'a, T, T, for<'r> fn(&'r T) -> &'r T> {
//
}
because then the type for K isn't tied to a specific lifetime. I wonder if I can do that somehow when I return K instead of & 'r K.
In your trait definiton you tell the compiler that F returns a K which outlives 'a (K: 'a in the generic).
So all you have to do is return something outliving the associated lifetime 'a from your impl:
struct Foo<'a, T: 'a, K: 'a, F>
where
for<'r> F: Fn(&'r T) -> K,
{
t: &'a T,
k: K,
f: F,
}
impl<'a, T: 'a> Foo<'a, T, &'a T, for<'r> fn(&'r T) -> &'a T> {
//
}
But it will probably be hard to generate something of lifetime 'a when all you get is something of lifetime 'r which does not have any bounds.
Maybe you don't want HRTBs after all:
struct Foo<'a, T: 'a, K: 'a, F>
where
F: Fn(&'a T) -> K,
{
t: &'a T,
k: K,
f: F,
}
impl<'a, T: 'a> Foo<'a, T, &'a T, fn(&'a T) -> &'a T> {
//
}
I have the following setup where I am trying to create a Dummy future which is intended to modify the values in-place inside the future obtained from f: FnMut(&mut i32) -> Fut. I am passing the generic function fun to substitute it, but I am getting different lifetimes.
#![allow(unused_variables)]
pub struct Dummy<Fut, F> {
f: F,
futures: futures::stream::FuturesUnordered<Fut>
}
impl<Fut, F> Dummy<Fut, F>
where
F: FnMut(&mut i32) -> Fut,
Fut: futures::Future<Output = ()>,
{
fn new(f: F) -> Self {
Self {
f,
futures: futures::stream::FuturesUnordered::new()
}
}
}
impl<Fut, F> futures::Future for Dummy<Fut, F>
where
F: FnMut(&mut i32) -> Fut,
Fut: futures::Future<Output = ()>
{
type Output = ();
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
// logic emitted
core::task::Poll::Ready(())
}
}
fn fun<'a>(f: &'a mut i32) -> impl futures::Future<Output = ()> + 'a {
async move {
*f += 1;
}
}
#[tokio::main]
async fn main() {
Dummy::new(fun).await;
}
playground link
which gives the compile-error:
error[E0308]: mismatched types
--> src/main.rs:45:20
|
45 | Dummy::new(fun).await;
| ^^^^^^ one type is more general than the other
|
= note: expected trait `for<'r> FnOnce<(&'r mut i32,)>`
found trait `for<'a> FnOnce<(&'a mut i32,)>`
= note: the lifetime requirement is introduced here
error[E0308]: mismatched types
--> src/main.rs:45:20
|
45 | Dummy::new(fun).await;
| ^^^^^^ one type is more general than the other
|
= note: expected trait `for<'r> FnOnce<(&'r mut i32,)>`
found trait `for<'a> FnOnce<(&'a mut i32,)>`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to 4 previous errors
Is it possible to annotate the impl in a way that removes these mismatched types error? I could annotate everything with 'static, as I have done here: playground link. But I was trying to avoid this solution since I want to mutually borrow dependent data in the future poll method.
The signature of fun() connects the lifetime of the reference with the lifetime of the future it returns. You need to specify the same kind of connection on the Future implementation of Dummy:
impl<'a, Fut, F> futures::Future for Dummy<Fut, F>
where
F: FnMut(&'a mut i32) -> Fut,
Fut: futures::Future<Output = ()> + 'a,
Playground
If I try to implement the trait Frob for functions like foo as follows:
fn foo<'b>(state: &'b mut i32) -> impl FnMut(&str) -> i32 + 'b {
move |i| *state
}
trait Frob<S, I, O> {
fn frob(self, state: &mut S, input: I) -> O;
}
impl<S, I, O, F, G> Frob<S, I, O> for F
where
F: FnMut(&mut S) -> G,
G: FnMut(I) -> O,
{
fn frob(mut self, state: &mut S, input: I) -> O {
self(state)(input)
}
}
fn bar() {
foo.frob(&mut 1, "hi");
}
I get the error
error[E0599]: the method `frob` exists for fn item `for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}`,
but its trait bounds were not satisfied
...
= note: the following trait bounds were not satisfied:
`<for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
which is required by `for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`
`<&for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
which is required by `&for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`
`<&mut for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
which is required by `&mut for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`
First of all, how do I interpret this error message? Second, how do I write the trait bound correctly? Presumably the problem has something to do with the returned closure hanging on to state, but I can't find a place to specify a lifetime for G.
First of all, how do I interpret this error message?
Yes, it is a tad cryptic isn't it? Two things to recognise:
<for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} is the compiler's very wordy way of expressing the type of function foo; and
the same note is repeated for that function type, a shared reference to that function type, and a mutable reference to that function type—this happens when the compiler attempts automatic referencing in method call syntax such as you have in foo.frob(...).
So we can quickly distill the error message down to:
error[E0599]: the method `frob` exists for fn item `{foo}`,
but its trait bounds were not satisfied
...
= note: the following trait bounds were not satisfied:
`<{foo} as FnOnce<(&mut _,)>>::Output = _`
which is required by `{foo}: Frob<_, _, _>`
The compiler is telling us that it found a potential frob method on {foo} but in order for it to be applicable, {foo}'s return type must match the constraints of the Frob trait (but it doesn't).
Second, how do I write the trait bound correctly? Presumably the problem has something to do with the returned closure hanging on to state, but I can't find a place to specify a lifetime for G.
You need to add the lifetime constraint to the trait (playground):
trait Frob<'b, S, I, O> {
fn frob(self, state: &'b mut S, input: I) -> O;
}
impl<'b, S: 'b, I, O, F, G> Frob<'b, S, I, O> for F
where
F: FnMut(&'b mut S) -> G,
G: 'b + FnMut(I) -> O,
{
fn frob(mut self, state: &'b mut S, input: I) -> O {
self(state)(input)
}
}
I've reduced my problem to the following code:
struct Struct<'a, 'b, T> {
a: &'a T,
b: &'b T,
}
trait Trait<'a, 'b, T> {
fn a(&self) -> &'a T;
fn b(&self) -> &'b T;
}
impl<'a, 'b, T> Trait<'a, 'b, T> for Struct<'a, 'b, T> {
fn a(&self) -> &'a T {
self.a
}
fn b(&self) -> &'b T {
self.b
}
}
struct Confused<T> {
field: T,
}
impl<T> Confused<T> {
fn foo<'a, 'b>(&'a self, param: &Struct<'a, 'b, T>) -> &'a T {
param.b();
param.a()
}
fn bar<'a, 'b, U: Trait<'a, 'b, T>>(&'a self, param: &U) -> &'a T {
param.b();
param.a()
}
}
The function foo is okay, but when I replace the concrete type Struct<'a, 'b, T> with a generic type U: Trait<'a, 'b, T>, I get the following error:
error[E0309]: the parameter type `T` may not live long enough
--> src/lib.rs:31:15
|
24 | impl<T> Confused<T> {
| - help: consider adding an explicit lifetime bound `T: 'b`...
...
31 | param.b();
| ^
|
note: ...so that the reference type `&'b T` does not outlive the data it points at
--> src/lib.rs:31:15
|
31 | param.b();
| ^
The suggestion to add the bound T: 'b doesn't make sense to me, since 'b is a parameter to bar(). How can I fix bar() to accept any implementation of Trait<'a, 'b, T> as a parameter?
When you write a generic type such as:
struct Foo<'a, T> {
a: &'a T,
}
Rust automatically adds an implicit restriction of the type T: 'a, because your reference to T cannot live longer than T itself. This is automatic because your type would not work without it.
But when you do something like:
impl<T> Foo {
fn bar<'a, 'b>() -> &'a T {/*...*/}
}
there is an automatic T: 'a but not a T: 'b because there is no &'b T anywhere.
The solution is to add those constraints by yourself. In your code it would be something like this:
impl<T> Confused<T> {
fn bar<'a, 'b, U: Trait<'a, 'b, T>>(&'a self, param: &U) -> &'a T
where
T: 'b, //<--- here!
{
param.b();
param.a()
}
}
Background
Closures in Rust have anonymous type and cannot be referred to as a known concrete type. However from Feb 2017, all non-capturing closures can be converted to anonymous functions and have the same type as a function pointer.
I wanted to create a type that standardizes curried closures. If we have a function fn(T1, T2, ...) -> R we can have a special type that is FnXXX(T2, ...) -> R (replace XXX with or Mut or Once, or Box). They can then be used inside containers without involving dynamic dispatch.
Attempt for FnOnce
The following works:
#![feature(unboxed_closures)]
#![feature(fn_traits)]
struct Curry0<T, R> {
f: fn(T) -> R,
v: T,
}
impl<T, R> FnOnce<()> for Curry0<T, R> {
type Output = R;
extern "rust-call" fn call_once(self, _: ()) -> R {
(self.f)(self.v)
}
}
fn curry<T, R>(f: fn(T) -> R, v: T) -> impl FnOnce() -> R {
Curry0 { f: f, v: v }
}
fn main() {
curry(|s| println!("{}", s), "Hello, World!")()
}
However, I am not able to add the following:
impl<'a, T, R> FnMut<()> for Curry0<&'a mut T, R> {
extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
(self.f)(self.v)
}
}
The error message:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/main.rs:16:18
|
16 | (self.f)(self.v)
| ^^^^^^
|
note: ...the reference is valid for the lifetime 'a as defined on the impl at 14:1...
--> src/main.rs:14:1
|
14 | impl<'a, T, R> FnMut<()> for Curry0<&'a mut T, R> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 15:5
--> src/main.rs:15:5
|
15 | / extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
16 | | (self.f)(self.v)
17 | | }
| |_____^
My understanding is that for this to work, call_mut must take care that &mut self only lives for the function itself, and so if f returns something that refers to v's inside, it will be invalid.
Attempt for FnMut
To work with FnMut rather than FnOnce above I wrote:
#![feature(unboxed_closures)]
#![feature(fn_traits)]
struct Curry0Mut<'a, 'b, T, R>
where
T: 'a,
R: 'b,
{
f: fn(&mut T) -> R,
v: &'a mut T,
_l: std::marker::PhantomData<&'b ()>,
}
impl<'a, 'b, T, R> FnOnce<()> for Curry0Mut<'a, 'b, T, R> {
type Output = R;
extern "rust-call" fn call_once(self, _: ()) -> R {
(self.f)(self.v)
}
}
impl<'a, 'b, T, R> FnMut<()> for Curry0Mut<'a, 'b, T, R>
where
T: 'a,
R: 'b,
{
extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
(self.f)(self.v)
}
}
fn curry<'a, T, R>(f: fn(&mut T) -> R, v: &'a mut T) -> impl FnMut() -> R + 'a {
Curry0Mut {
f: f,
v: v,
_l: std::marker::PhantomData,
}
}
fn main() {
let mut v = "Hello, World".to_owned();
curry(|s| println!("{}", s), &mut v)();
}
This is more complicated and sadly we have two structs for just slightly different usage. When I looked closer at the change I have to make here, I figured out that f is actually a generic function on its parameter's lifetime, and T's lifetime is independent to this. We also have to make sure R does not live longer than the closure itself, so its lifetime has to be encoded inside the closure.
I will not go into detail for Fn as it is similar. Only to note that this makes it worse as we need another variation of Curry0, because &mut T is not &T.
The Question
Is it possible to express the fact that v has a different lifetime expectation than fs parameter?
For example, how to write something like:
struct Curry0<'a, 'b, T, R>
where
R: 'b,
{
f: fn(T) -> R, //T have generic lifetime
v: T, //T: 'a
_a: std::marker::PhantomData<&'a ()>,
_b: std::marker::PhantomData<&'b ()>,
}