There are multiple Range types. Some Range types implement Iterator. I want to take all Range types that implement Iterator as a struct field.
This is my approach:
pub trait RangeBoundsExt<T: PartialOrd<T>>: Iterator<Item = T> {
// some methods
}
impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::Range<T> {}
impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::RangeFrom<T> {}
impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::RangeInclusive<T> {}
pub struct Foo<T> {
range: Box<dyn RangeBoundsExt<T>>
}
Playground
But I am getting this error:
Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `T: std::iter::Step` is not satisfied
--> src/lib.rs:7:24
|
7 | impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::Range<T> {}
| ^^^^^^^^^^^^^^^^^ the trait `std::iter::Step` is not implemented for `T`
|
= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::Range<T>`
help: consider further restricting this bound
|
7 | impl<T: PartialOrd<T> + std::iter::Step> RangeBoundsExt<T> for std::ops::Range<T> {}
| ^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `T: std::iter::Step` is not satisfied
--> src/lib.rs:9:24
|
9 | impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::RangeFrom<T> {}
| ^^^^^^^^^^^^^^^^^ the trait `std::iter::Step` is not implemented for `T`
|
= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::RangeFrom<T>`
help: consider further restricting this bound
|
9 | impl<T: PartialOrd<T> + std::iter::Step> RangeBoundsExt<T> for std::ops::RangeFrom<T> {}
| ^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `T: std::iter::Step` is not satisfied
--> src/lib.rs:11:24
|
11 | impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::RangeInclusive<T> {}
| ^^^^^^^^^^^^^^^^^ the trait `std::iter::Step` is not implemented for `T`
|
= note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::RangeInclusive<T>`
help: consider further restricting this bound
|
11 | impl<T: PartialOrd<T> + std::iter::Step> RangeBoundsExt<T> for std::ops::RangeInclusive<T> {}
| ^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
Range does not guarantee an Iterator implementation. It only provides one if the type implements Step. Likewise, RangeTo does not guarantee a lack of an Iterator implementation. It simply just doesn't provide one by default. To fix your error, you simply have to require that there is an iterator definition for the range:
// note the additional 'where' requirement
impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::Range<T> where
std::ops::Range<T>: Iterator<Item = T>
{
}
impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::RangeFrom<T> where
std::ops::RangeFrom<T>: Iterator<Item = T>
{
}
impl<T: PartialOrd<T>> RangeBoundsExt<T> for std::ops::RangeInclusive<T> where
std::ops::RangeInclusive<T>: Iterator<Item = T>
{
}
Related
On the code below, you can see that I'm trying to clone a: A where A derives Clone
use std::sync::Arc;
pub trait S{}
struct B{
}
impl S for B{
}
#[derive(Clone)]
struct A<T: ?Sized>{
a: Arc<Box<T>>
}
fn main() {
let a: A<dyn S> = A{
a: Arc::new(Box::new(B{}))
};
a.clone();
}
Playground
However I get this error:
Error:
Compiling playground v0.0.1 (/playground)
error[E0599]: the method `clone` exists for struct `A<dyn S>`, but its trait bounds were not satisfied
--> src/main.rs:22:7
|
3 | pub trait S{}
| ----------- doesn't satisfy `dyn S: Clone`
...
13 | struct A<T: ?Sized>{
| -------------------
| |
| method `clone` not found for this
| doesn't satisfy `A<dyn S>: Clone`
...
22 | a.clone();
| ^^^^^ method cannot be called on `A<dyn S>` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`dyn S: Clone`
which is required by `A<dyn S>: Clone`
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `clone`, perhaps you need to implement it:
candidate #1: `Clone`
Shouldn't A implement Clone for any T, since the clone on A would simply call A {a: old_a.clone()} which since it's an Arc it always implement clone?
Shouldn't it be guaranteed that A implements Clone because of #[derive(Clone)]?
This is an issue with the implementation of the derive macro for Clone. It doesn't work with structs containing generic types that don't implement clone themselves: https://github.com/rust-lang/rust/issues/41481
In that case you'll have to implement Clone manually, which is, as you say, pretty easy.
impl<T> Clone for A<T> {
fn clone(&self) -> A<T> {
A { a: self.a.clone() }
}
}
Following code causes conflicting implementations error:
trait A<S> {}
trait B<S> {}
struct C<T>(T);
impl <T, S> B<S> for T
where T: A<S>
{}
impl<T, S> B<S> for C<T>
where T: B<S>
{}
Compiling playground v0.0.1 (/playground)
error[E0119]: conflicting implementations of trait `B<_>` for type `C<_>`:
--> src/lib.rs:11:1
|
7 | / impl <T, S> B<S> for T
8 | | where T: A<S>
9 | | {}
| |__- first implementation here
10 |
11 | / impl<T, S> B<S> for C<T>
12 | | where T: B<S>
13 | | {}
| |__^ conflicting implementation for `C<_>`
|
= note: downstream crates may implement trait `A<_>` for type `C<_>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0119`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
C is a local type, can specialization resolve this problem?
Moreover, it works if we replace A<S> with Fn(S), is a compiler hole?
trait B<S> {}
struct C<T>(T);
impl <T, S> B<S> for T
where T: Fn(S)
{}
impl<T, S> B<S> for C<T>
where T: B<S>
{}
I'd like to define a trait Holder that can iterate some through the items method. I don't want to return a trait object from this method because I'd like to stick with static dispatch and stack allocation if possible. The system I have works fine, but fails in a sort of surprising situation.
Here's the code:
pub trait Holder<'a, N: 'a> {
type Items: Iterator<Item=&'a N>;
fn items(&'a self) -> Self::Items;
}
struct Impl<N> {
items: Vec<N>
}
impl<'a, N: 'a> Holder<'a, N> for Impl<N> {
type Items = std::slice::Iter<'a, N>;
fn items(&'a self) -> Self::Items {
self.items.iter()
}
}
fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
// COMPILE ERROR
for item in holder.items() {
}
}
Here's the error:
error[E0309]: the parameter type `impl Holder<'a, N>` may not live long enough
--> src/graph/test.rs:20:17
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
| ------------------ help: consider adding an explicit lifetime bound...: `impl Holder<'a, N> + 'a`
20 | for item in holder.items() {
| ^^^^^^
|
note: ...so that the type `impl Holder<'a, N>` is not borrowed for too long
--> src/graph/test.rs:20:17
|
20 | for item in holder.items() {
| ^^^^^^
error[E0309]: the parameter type `impl Holder<'a, N>` may not live long enough
--> src/graph/test.rs:20:24
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N>) {
| ------------------ help: consider adding an explicit lifetime bound...: `impl Holder<'a, N> + 'a`
20 | for item in holder.items() {
| ^^^^^
|
note: ...so that the reference type `&'a impl Holder<'a, N>` does not outlive the data it points at
--> src/graph/test.rs:20:24
|
20 | for item in holder.items() {
| ^^^^^
error: aborting due to 2 previous errors; 4 warnings emitted
For more information about this error, try `rustc --explain E0309`.
I follow the compiler's advice and add the explicit lifetime:
pub trait Holder<'a, N: 'a> {
type Items: Iterator<Item=&'a N>;
fn items(&'a self) -> Self::Items;
}
struct Impl<N> {
items: Vec<N>
}
impl<'a, N: 'a> Holder<'a, N> for Impl<N> {
type Items = std::slice::Iter<'a, N>;
fn items(&'a self) -> Self::Items {
self.items.iter()
}
}
fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N> + 'a) {
for item in holder.items() {
}
}
Which gives the error:
error[E0597]: `holder` does not live long enough
--> src/graph/test.rs:20:17
|
19 | fn use_holder<'a, N: 'a>(holder: impl Holder<'a, N> + 'a) {
| -- lifetime `'a` defined here
20 | for item in holder.items() {
| ^^^^^^--------
| |
| borrowed value does not live long enough
| argument requires that `holder` is borrowed for `'a`
...
23 | }
| - `holder` dropped here while still borrowed
I've seen this question and several other tangentially related to this problem, but can't understand how to move forward.
Other than returning a trait object from Hoder#items, what are my options to get the loop in use_hodler working?
This was actually very difficult - lifetimes and associated types appears to be one of those weird corner cases in Rust that is not (yet) well supported. I'd be lying if I said I properly understood the reasons for the error, however I've managed to get this to work for this specific example using Higher Ranked Trait Bounds.
You only need to change one line:
fn use_holder<N>(holder: impl for<'a> Holder<'a, N>) {
Note that the lifetime parameter has moved to the for<'a>. What this means is that the holder parameter implements Holder<'a, N> for every possible lifetime 'a, rather than for a specific 'a that lives at least as long as the function.
You'd need to use for<'a> ... most of the places you use this trait, so it will become messy quite quickly. And higher ranked trait bounds is not a commonly used feature: It's pretty niche and has been elided for the most common cases, so it's not going to help with legibility or maintainability.
I'd recommend changing your architecture to avoid this construction if at all possible.
The following code:
use std::marker::PhantomData;
trait MyTrait {
const FOO: usize;
}
struct MyStruct<T: MyTrait> {
v: [u32; <T as MyTrait>::FOO],
p: PhantomData<T>,
}
gives me the following compilation error:
error[E0277]: the trait bound `T: MyTrait` is not satisfied
--> src/lib.rs:8:14
|
4 | const FOO: usize;
| ----------------- required by `MyTrait::FOO`
...
7 | struct MyStruct<T: MyTrait> {
| -- help: consider further restricting this bound: `T: MyTrait +`
8 | v: [u32; <T as MyTrait>::FOO],
| ^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `T`
(Link to the playground)
How can I successfully use FOO when defining my vector?
At the moment, you can't.
Array lengths cannot use generic parameters. This is an issue that results from the way constants and generics are implemented and interact with each other in the compiler and has been worked on for a few years with slow improvements.
I defined a trait:
pub trait SaySomething {
fn say(&self) {
println!("{:?} can't speak", self);
}
}
I get the error:
error[E0277]: `Self` doesn't implement `std::fmt::Debug`
--> src/lib.rs:3:38
|
3 | println!("{:?} can't speak", self);
| ^^^^ `Self` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
= help: the trait `std::fmt::Debug` is not implemented for `Self`
= help: consider adding a `where Self: std::fmt::Debug` bound
= note: required because of the requirements on the impl of `std::fmt::Debug` for `&Self`
= note: required by `std::fmt::Debug::fmt`
So I tried:
use std::fmt::Debug;
pub trait SaySomething {
fn say<Self: Debug>(self: &Self) {
println!("{:?} can't speak", self);
}
}
I get the error:
error: expected identifier, found keyword `Self`
--> src/lib.rs:4:12
|
4 | fn say<Self: Debug>(self: &Self) {
| ^^^^ expected identifier, found keyword
error[E0194]: type parameter `Self` shadows another type parameter of the same name
--> src/lib.rs:4:12
|
3 | / pub trait SaySomething {
4 | | fn say<Self: Debug>(self: &Self) {
| | ^^^^ shadows another type parameter
5 | | println!("{:?} can't speak", self);
6 | | }
7 | | }
| |_- first `Self` declared here
error[E0307]: invalid method receiver type: &Self
--> src/lib.rs:4:31
|
4 | fn say<Self: Debug>(self: &Self) {
| ^^^^^
|
= note: type must be `Self` or a type that dereferences to it
= help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>`
You need to constrict your trait to types that implement Debug.
pub trait SaySomething: std::fmt::Debug {
fn say(&self) {
println!("{:?} can't speak", self);
}
}