I want to implement an enum that holds either a Box or a mutable reference that should be convertible from either of the two:
pub enum BoxOrMutRef<'a, T: ?Sized + 'a> {
Boxed(Box<T>),
MutRef(&'a mut T),
}
impl<'a, T: ?Sized + 'a> From<&'a mut T> for BoxOrMutRef<'a, T> {
fn from(v: &'a mut T) -> BoxOrMutRef<'a, T> {
BoxOrMutRef::MutRef(v)
}
}
impl<'a, T> From<T> for BoxOrMutRef<'a, T> {
fn from(v: T) -> BoxOrMutRef<'a, T> {
BoxOrMutRef::Boxed(Box::new(v))
}
}
When I try to use these conversion functions for dyn traits...
trait MyTrait {}
fn test1<'a>(v: impl Into<BoxOrMutRef<'a, dyn MyTrait>>) {}
struct MyStruct {}
impl MyTrait for MyStruct {}
fn main() {
let mut v = MyStruct {};
test1(&mut v);
test1(v);
}
Playground
It fails with:
error[E0277]: the trait bound `BoxOrMutRef<'_, dyn MyTrait>: std::convert::From<&mut MyStruct>` is not satisfied
--> src/main.rs:28:5
|
20 | fn test1<'a>(v: impl Into<BoxOrMutRef<'a, dyn MyTrait>>) {}
| ----- ---------------------------------- required by this bound in `test1`
...
28 | test1(&mut v);
| ^^^^^ the trait `std::convert::From<&mut MyStruct>` is not implemented for `BoxOrMutRef<'_, dyn MyTrait>`
|
= help: the following implementations were found:
<BoxOrMutRef<'a, T> as std::convert::From<&'a mut T>>
<BoxOrMutRef<'a, T> as std::convert::From<T>>
= note: required because of the requirements on the impl of `std::convert::Into<BoxOrMutRef<'_, dyn MyTrait>>` for `&mut MyStruct`
error[E0277]: the trait bound `BoxOrMutRef<'_, dyn MyTrait>: std::convert::From<MyStruct>` is not satisfied
--> src/main.rs:29:5
|
20 | fn test1<'a>(v: impl Into<BoxOrMutRef<'a, dyn MyTrait>>) {}
| ----- ---------------------------------- required by this bound in `test1`
...
29 | test1(v);
| ^^^^^ the trait `std::convert::From<MyStruct>` is not implemented for `BoxOrMutRef<'_, dyn MyTrait>`
|
= help: the following implementations were found:
<BoxOrMutRef<'a, T> as std::convert::From<&'a mut T>>
<BoxOrMutRef<'a, T> as std::convert::From<T>>
= note: required because of the requirements on the impl of `std::convert::Into<BoxOrMutRef<'_, dyn MyTrait>>` for `MyStruct`
Using test1(&mut v as &mut dyn MyTrait) works, but I want to avoid explicit casts here. How do I have to change my From implementations to allow these conversions?
Related
I'm trying to implement a trait for all containers that implement iter(), ie. for all containers that provide an IntoIterator<Item=&'a T>. I've tried this, but unfortunately, even for the simplest case it is failing. Maybe someone knows what I'm doing wrong?
trait Monotonic<'a, T: 'a + ?Sized> {
fn is_monotonic(&mut self) -> bool {
return true;
}
}
impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C
where C: IntoIterator<Item=&'a T> + ?Sized {}
fn main() {
let v = vec![1u32, 2u32, 3u32];
if v.is_monotonic() {
print!("Is monotonic!");
}
}
The compiler complains about not satisfied bounds:
error[E0599]: the method `is_monotonic` exists for struct `Vec<u32>`, but its trait bounds were not satisfied
--> src/test.rs:13:10
|
13 | if v.is_monotonic() {
| ^^^^^^^^^^^^ method cannot be called on `Vec<u32>` due to unsatisfied trait bounds
--> /rustc/fc594f15669680fa70d255faec3ca3fb507c3405/library/alloc/src/vec/mod.rs:400:1
|
| = note: doesn't satisfy `<Vec<u32> as IntoIterator>::Item = &_`
= note: doesn't satisfy `Vec<u32>: Monotonic<'_, _>`
|
note: trait bound `[u32]: IntoIterator` was not satisfied
--> src/test.rs:8:10
|
7 | impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C
| ---------------- -
8 | where C: IntoIterator<Item=&'a T> + ?Sized {}
| ^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here
note: the following trait bounds were not satisfied:
`<Vec<u32> as IntoIterator>::Item = &_`
`<[u32] as IntoIterator>::Item = &_`
--> src/test.rs:8:23
|
7 | impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C
| ---------------- -
8 | where C: IntoIterator<Item=&'a T> + ?Sized {}
| ^^^^^^^^^^ unsatisfied trait bound introduced here
error: aborting due to previous error
For more information about this error, try `rustc --explain E0599`.
I've already tried to solve this on my own, but after several attempts I'm at a point where some help would be highly appreciated!
According to its documentation, Vec<T> implements the following IntoIterator traits:
IntoIterator<Item = &'a T> for &'a Vec<T, A>
IntoIterator<Item = &'a mut T> for &'a mut Vec<T, A>
IntoIterator<Item = T> for Vec<T, A>
The variable v you are calling it on is a Vec<u32>, which only implements IntoIterator<Item = u32>, and not any kind of &'a u32 as your trait requires.
There are a couple of solutions. The first one is to run the code on &v:
trait Monotonic<'a, T: 'a + ?Sized> {
fn is_monotonic(&mut self) -> bool {
return true;
}
}
impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C where C: IntoIterator<Item = &'a T> + ?Sized {}
fn main() {
let v = vec![1u32, 2u32, 3u32];
if (&v).is_monotonic() {
print!("Is monotonic!");
}
}
Although that's probably not what you want, because I read from your question that you want your Monotonic trait to be implemented as generically as possible. For that, simply remove the & requirement:
trait Monotonic<'a, T: 'a + ?Sized> {
fn is_monotonic(&mut self) -> bool {
return true;
}
}
impl<'a, T: 'a + ?Sized, C> Monotonic<'a, T> for C where C: IntoIterator<Item = T> + ?Sized {}
fn main() {
let mut v = vec![1u32, 2u32, 3u32];
if v.is_monotonic() {
print!("Is monotonic!");
}
}
Couple of remarks concerning your current code structure, though:
While this technically compiles, it won't be possible to implement your function. IntoIterator consumes the object you call it on, but your is_monotonic function only has &mut access to it, so you won't ever be able to call into_iter here.
What you probably want instead is to have is_monotonic consume the value, but then only implement it for &T.
Your Monotonic function doesn't require any generic parameters, so remove them.
trait Monotonic {
fn is_monotonic(self) -> bool;
}
impl<'a, T, C> Monotonic for &'a C
where
&'a C: IntoIterator<Item = T>,
{
fn is_monotonic(self) -> bool {
let mut iter = self.into_iter();
// Do something with iter
let x = iter.next().unwrap();
// Return result
true
}
}
fn main() {
let v = vec![1u32, 2u32, 3u32];
if v.is_monotonic() {
print!("Is monotonic!");
}
}
Here is an example implementation of is_monotonic, assuming it means monotonic rising:
trait Monotonic {
fn is_monotonic(self) -> bool;
}
impl<'a, T, C> Monotonic for &'a C
where
&'a C: IntoIterator<Item = T>,
T: PartialOrd,
{
fn is_monotonic(self) -> bool {
let mut iter = self.into_iter();
if let Some(first) = iter.next() {
let mut previous = first;
for next in iter {
if !next.ge(&previous) {
return false;
}
previous = next;
}
true
} else {
// An iterator without elements is monotonic.
// Although that's probably up for philosophical debate.
true
}
}
}
fn main() {
let v = vec![1u32, 2u32, 3u32];
if v.is_monotonic() {
println!("Is monotonic!");
}
println!("{:?}", v);
}
Is monotonic!
[1, 2, 3]
Below I have
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(
&self
) -> Result<
which shouldn't need &'a self because the 'a already comes from MyPolynomial<'a, T>. Also, I should pass &'a[T] in PolyIterator::new in the line
let iterator = PolyIterator::new(self.coefficients.as_life_ref());
but I'm getting an error saying that it wants a &'a (dyn Mem<'a, T> + 'a) which I have no idea why.
pub trait Mem<'r, T>
{
fn as_life_ref(&'r self) -> &'r [T];
}
pub struct PolyIterator<'a, T> {
coefficients: &'a [T]
}
impl<'a, T> PolyIterator<'a, T> {
pub fn new(coefficients: &'a[T]) -> PolyIterator<'a, T> {
todo!()
}
}
pub struct MyPolynomial<'a, T> {
coefficients: Box<dyn Mem<'a, T> + 'a>,
}
pub trait AsPolyIterator<'a, T> {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(
&self
) -> Result<
PolyIterator<'a, T>,
(),
> {
let iterator = PolyIterator::new(self.coefficients.as_life_ref());
todo!()
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c3e657136252b96cd5aca91efeaea56f
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:31:54
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/lib.rs:26:3
|
26 | &self
| ^^^^^
note: ...so that reference does not outlive borrowed content
--> src/lib.rs:31:36
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
--> src/lib.rs:24:6
|
24 | impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
| ^^
note: ...so that the types are compatible
--> src/lib.rs:31:54
|
31 | let iterator = PolyIterator::new(self.coefficients.as_life_ref());
| ^^^^^^^^^^^
= note: expected `&'a (dyn Mem<'a, T> + 'a)`
found `&(dyn Mem<'a, T> + 'a)`
Your trait definition and implementation do not line up:
pub trait AsPolyIterator<'a, T> {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()>;
}
impl<'a, T> AsPolyIterator<'a, T> for MyPolynomial<'a, T> {
fn as_poly_iterator(&self) -> Result<PolyIterator<'a, T>, ()> { ... }
}
The trait has PolyIterator bound to self, while the implementation has it bound elsewhere, these are not compatible.
It should definitely be &'a self since the PolyIterator is derived from self.coefficients, but you should use a different lifetime 'b for MyPolynomial to avoid over-constraining:
impl<'a, 'b, T> AsPolyIterator<'a, T> for MyPolynomial<'b, T> where 'a: 'b {
fn as_poly_iterator(&'a self) -> Result<PolyIterator<'a, T>, ()> { ... }
}
Mind the where 'a: 'b since that ensures the lifetime 'b is larger than 'a. See it working on the playground.
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
I have a struct with a lifetime:
struct HasLifetime<'a>( /* ... */ );
There is there is an implementation of the trait Foo:
impl<'a, 'b: 'a> Foo for &'a mut HasLifetime<'b> { }
I want to implement the following function:
fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut Lifetime<'b>) -> impl Foo {
bar
}
This won't compile because the returned impl is only valid for 'a. However, specifying impl Foo + 'a results in:
error[E0909]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> src/main.rs:7:60
|
7 | fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut HasLifetime<'b>) -> impl Trait + 'a {
| ^^^^^^^^^^^^^^^
|
note: hidden type `&'a mut HasLifetime<'b>` captures the lifetime 'b as defined on the function body at 7:1
--> src/main.rs:7:1
|
7 | fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut HasLifetime<'b>) -> impl Trait + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The seemingly equivalent function with a boxed trait object compiles:
fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut Lifetime<'b>) -> Box<Foo + 'a> {
Box::new(bar)
}
How can I define bar_to_foo with impl Trait?
Playground link
You need to indicate that the returned value is built upon multiple lifetimes. However, you can't use multiple lifetime bounds with impl Trait, and attempting to do so doesn't have a useful error message.
There's a trick you can use that involves creating a dummy trait that has a lifetime parameter:
trait Captures<'a> {}
impl<'a, T: ?Sized> Captures<'a> for T {}
fn bar_to_foo<'a, 'b: 'a>(bar: &'a mut HasLifetime<'b>) -> impl Trait + Captures<'b> + 'a {
bar
}
Thankfully, this only occurs when the "hidden" lifetime is invariant, which occurs because the reference is mutable.
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}
}
}