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.
Related
I have a trait Foo. This has a method which takes a generic type implementing Bar and is therefore not object safe:
trait Bar {}
trait Foo {
fn foofunc<B: Bar>(&self, b: B);
}
I want to make the trait Foo object safe. I gather the usual way to do this is to wrap it in a new, object-safe, trait (see here). Something along the lines of:
trait FooObjectSafe<B>
where B: Bar,
{
fn foofunc(&self, b: B);
}
impl<B, F> FooObjectSafe<B> for F
where B: Bar,
F: Foo,
{
fn foofunc(&self, b: B) {
Foo::foofunc(self, b)
}
}
This seems very limiting however. If there is a function use_foo which takes a generic type implementing Foo, then it cannot be used with FooObjectSafe without changing its signature (I don't want to do this as in practise these functions come from different modules and are very divorced from one another):
struct BarImpl;
impl Bar for BarImpl {}
struct FooImpl;
impl Foo for FooImpl {
fn foofunc<B: Bar>(&self, b: B) {}
}
fn main() {
let foos = [
Box::new(FooImpl{}) as Box<dyn FooObjectSafe<BarImpl>>,
Box::new(FooImpl{})
];
use_foo(foos[0]);
}
results in the error
error[E0277]: the trait bound `Box<dyn FooObjectSafe<BarImpl>>: Foo` is not satisfied
--> src/main.rs:43:13
|
43 | use_foo(foos[0]);
| ------- ^^^^^^^ the trait `Foo` is not implemented for `Box<dyn FooObjectSafe<BarImpl>>`
| |
| required by a bound introduced by this call
|
= help: the trait `Foo` is implemented for `FooImpl`
note: required by a bound in `use_foo`
--> src/main.rs:9:14
|
8 | fn use_foo<F>(foo: F)
| ------- required by a bound in this
9 | where F: Foo,
| ^^^ required by this bound in `use_foo`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to previous error
Is there a better way to do this? I suspect I'm making some architectural faux pas here, but what exactly?
Playground
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() }
}
}
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>
{
}
I have a trait, and to implement that trait, I would like to require the implementor to implement AddAssign; however, doing that results in my trait seemingly needing to require Sized:
trait Foo: ::std::ops::AddAssign {}
trait Bar: Iterator {}
(playground)
Bar compiles fine; Foo, however:
error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied
--> src/main.rs:1:1
|
1 | trait Foo: ::std::ops::AddAssign {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Self` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Self`
= help: consider adding a `where Self: std::marker::Sized` bound
= note: required by `std::ops::AddAssign`
If I add + Sized to the trait bounds, all is fine, but… why do I need to do this? Why doesn't AddAssign need this?
Let's look at the definition of the trait:
pub trait AddAssign<Rhs = Self> {
fn add_assign(&mut self, rhs: Rhs);
}
That is, trait Foo: ::std::ops::AddAssign is equivalent to trait Foo: ::std::ops::AddAssign<Foo> and add_assign takes a Rhs as its second parameter, hence Rhs needs to be sized.
Note that trait Foo: ::std::ops::AddAssign<u32> does not require Foo to be sized.
Suppose I want to create some type that wraps some other generic type, like so:
struct MyWrapper<T> {
pub inner: T,
}
Now I want my type to have a method if the inner type satisfies a specific bound. For example: I want to print it (in this example without using fmt traits for simplicity). To do this I have two possibilities: adding a bound to the impl or to the method itself.
Method Bound
impl<T> MyWrapper<T> {
pub fn print_inner(&self) where T: std::fmt::Display {
println!("[[ {} ]]", self.inner);
}
}
When calling this function with a MyWrapper<()> I get:
error[E0277]: `()` doesn't implement `std::fmt::Display`
--> src/main.rs:20:7
|
20 | w.print_inner();
| ^^^^^^^^^^^ `()` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
|
= help: the trait `std::fmt::Display` is not implemented for `()`
Impl Bound
impl<T: std::fmt::Display> MyWrapper<T> {
pub fn print_inner(&self) {
println!("[[ {} ]]", self.inner);
}
}
Calling it incorrectly again, gives:
error[E0599]: no method named `print_inner` found for type `MyWrapper<()>` in the current scope
--> src/main.rs:19:7
|
1 | struct MyWrapper<T> {
| ------------------- method `print_inner` not found for this
...
19 | w.print_inner();
| ^^^^^^^^^^^
|
= note: the method `print_inner` exists but the following trait bounds were not satisfied:
`() : std::fmt::Display`
My question is: what is more idiomatic? Are there semantic differences (aside from lifetime stuff with traits, explained here)? Are there differences apart from the compiler message?
One semantic difference is that with the type bound on the method you can partially implement a trait:
trait Trait {
fn f(self) where Self: std::fmt::Display;
fn g(self);
}
struct Struct<T>(T);
impl<T> Trait for Struct<T> {
fn f(self) where Struct<T>: std::fmt::Display {
println!("{}", self);
}
fn g(self) {
println!("Hello world!");
}
}
fn main() {
let s = Struct(vec![1]);
// f is not implemented, but g is
//s.f();
s.g();
}
This may be useful if you have many optional methods with different type bounds, which would otherwise require separate traits.