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> {
//
}
Related
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)
}
}
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)
}
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()
}
}
I tried to implement a function that maps over an iterator using a HashMap:
use std::collections::HashMap;
use std::hash::Hash;
/// Translates every element it gets using a map. In case the map does not help, it is mapped to
/// itself.
fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
where
S: Iterator<Item = T> + 'b,
T: Copy + Eq + Hash,
{
stream.map(|e: T| -> T { *map.get(&e).unwrap_or(&e) })
}
playground
I get an error message for this code:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:11:16
|
11 | stream.map(|e: T| -> T { *map.get(&e).unwrap_or(&e) })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 6:14...
--> src/lib.rs:6:14
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^
= note: ...so that the types are compatible:
expected &&std::collections::HashMap<T, T>
found &&'a std::collections::HashMap<T, T>
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:18...
--> src/lib.rs:6:18
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^
note: ...so that return value is valid for the call
--> src/lib.rs:6:66
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I have not figured out what is wrong or how I can solve it.
I have to guess, as you didn't include a MCVE. Your code doesn't compile, with lifetime errors on the surface. The function signature you probably meant is:
fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a
where
S: Iterator<Item = T> + 'b,
T: Copy + Eq + Hash,
'b: 'a, // Read: "'b outlives 'a"
As S might outlive your return value, and it would still be valid.
However I do not see any advantages of this approach: A longer lifetime is always valid in place of a shorter one, you don't explicitly need to call that out. Simply use a single lifetime, like below.
fn translate<'a, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a
where
S: Iterator<Item = T> + 'a,
T: Copy + Eq + Hash,
{
stream.map(move |e: T| -> T { *map.get(&e).unwrap_or(&e) })
}
As you see, you are also missing the move keyword, which your closure absolutely requires. Otherwise, it might outlive your map, which is owned by the function.
Still, this function is quite dense. If you only use it in a single place, maybe don't introduce it at all, and save some headaches?
This snippet does not compile because of a compiler bug:
struct Theory<'a, T: 'a> {
left: &'a T,
}
pub struct Contain<'a, T: 'a, U>
where
&'a T: IntoIterator,
for<'x> <(&'a T) as IntoIterator>::Item: PartialEq<&'x U>,
{
theory: Theory<'a, T>,
right: U,
}
impl<'a, T: 'a, U> Drop for Contain<'a, T, U>
where
&'a T: IntoIterator,
for<'x> <(&'a T) as IntoIterator>::Item: PartialEq<&'x U>,
{
fn drop(&mut self) {
//TODO
}
}
fn main() {}
I need this because I must compare the iterator Items with U; but Item is a reference type, because I call into_iter() in a borrowed collection.
I then tried something like this to work around:
struct Theory<'a, T: 'a> {
left: &'a T,
}
pub struct Contain<'a, 'b: 'a, T: 'a, U: 'b>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<&'b U>,
{
theory: Theory<'a, T>,
right: U,
_marker: ::std::marker::PhantomData<&'b ()>,
}
impl<'a, 'b, T: 'a, U> Drop for Contain<'a, 'b, T, U>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<&'b U>,
{
fn drop(&mut self) {
for left in self.theory.left.into_iter() {
if left == &self.right {
return;
}
}
//handle case where all lefts are different of right
}
}
fn main() {}
But I got a:
cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/main.rs:22:24
|
22 | if left == &self.right {
| ^^^^^^^^^^^
|
How can I iterate over left, then compare each elements with right?
You can simply require the trait bound PartialEq<B>. The methods eq and ne from the trait take all arguments by reference, so there is no reason why requiring PartialEq for a reference to a type.
So this works:
impl<'a, 'b, T: 'a, U> Drop for Contain<'a, 'b, T, U>
where
&'a T: IntoIterator,
<(&'a T) as IntoIterator>::Item: PartialEq<U>, // <-- change 1
{
fn drop(&mut self) {
for left in self.theory.left.into_iter() {
if left == self.right { // <-- change 2
return;
}
}
//handle case where all lefts are different of right
}
}