This question already has answers here:
How to test for equality between trait objects?
(3 answers)
The trait cannot be made into an object
(3 answers)
Closed 2 years ago.
I want to make a custom type that accepts any object implementing a trait that extends PartialEq.
Playground
// In the external crate
// Actual Type:-
// [webdriver::command::ExtensionCommand](https://docs.rs/webdriver/0.40.2/webdriver/command/enum.WebDriverExtensionCommand.html)
pub trait Foo: Send + Clone + PartialEq {}
// Actual Type:-
// [webdriver::command::WebDriverCommand](https://docs.rs/webdriver/0.40.2/webdriver/command/enum.WebDriverCommand.html)
pub struct Bar<T: Foo> {
foo: T,
}
// In my crate
type BarTwo = Bar<Box<dyn Foo>>;
I can not change the trait or struct because these types are not in my crate. I can not use generic types for BarTwo.
Output
error[E0038]: the trait `Foo` cannot be made into an object
--> src/lib.rs:12:23
|
4 | pub trait Foo : Send + Clone + PartialEq{}
| --- --------- ...because it uses `Self` as a type parameter in this
| |
| this trait cannot be made into an object...
...
12 | type BarTwo = Bar<Box<dyn Foo>>;
| ^^^^^^^ the trait `Foo` cannot be made into an object
Related
This question already has answers here:
Store a collection of heterogeneous types with generic type parameters in Rust
(1 answer)
How do I create a heterogeneous collection of objects?
(1 answer)
What is the cited problem with using generic type parameters in trait objects?
(2 answers)
Closed 2 years ago.
I am trying to push an object which implements a trait with a trait parameter into a Vec:
trait IRequest {}
trait IRequestHandler<T>
where
T: IRequest,
{
fn handle(&self, request: T);
}
pub struct CreateTodoRequest();
impl IRequest for CreateTodoRequest {}
pub struct CreateTodoRequestHandler();
impl IRequestHandler<CreateTodoRequest> for CreateTodoRequestHandler {
fn handle(&self, request: CreateTodoRequest) {}
}
fn main() {
let request = CreateTodoRequest {};
let handler = CreateTodoRequestHandler();
let mut handlers: Vec<&dyn IRequestHandler<dyn IRequest>> = Vec::new();
handlers.push(&handler);
}
I get an error:
error[E0277]: the trait bound `CreateTodoRequestHandler: IRequestHandler<dyn IRequest>` is not satisfied
--> src/main.rs:25:19
|
25 | handlers.push(&handler);
| ^^^^^^^^ the trait `IRequestHandler<dyn IRequest>` is not implemented for `CreateTodoRequestHandler`
|
= help: the following implementations were found:
<CreateTodoRequestHandler as IRequestHandler<CreateTodoRequest>>
= note: required for the cast to the object type `dyn IRequestHandler<dyn IRequest>`
When I had IRequestHandler without a parameter, I could cast it and push into the Vec. The problem only appears when the trait has a parameter.
Is it possible to cast an object to a trait with a parameter that it implements?
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.
This question already has answers here:
Why doesn't Rust support trait object upcasting?
(5 answers)
How do I clone a Rc trait object and cast it to another trait object?
(2 answers)
Closed 2 years ago.
// traits describing aspects of functionality needed elsewhere
trait A {}
trait B {}
// provider of functionality is always expected to support both
trait AB {}
impl<T: A + B> AB for T {}
struct Provider0 {}
impl A for Provider0 {}
impl B for Provider0 {}
// provider is picked dynamically at runtime
fn new_ab(i: u8) -> Box<dyn AB> {
match i {
0 => Box::new(Provider0 {}),
_ => unimplemented!(),
}
}
use std::sync::Arc;
fn use_a(a: Arc<dyn A>) {}
fn use_b(b: Arc<dyn B>) {}
fn run() {
let x = new_ab(0);
let x: Arc<dyn AB> = Arc::from(x);
use_a(x.clone());
use_b(x);
}
error[E0308]: mismatched types
--> src/lib.rs:28:11
|
28 | use_a(x.clone());
| ^^^^^^^^^ expected trait `A`, found trait `AB`
|
= note: expected struct `std::sync::Arc<(dyn A + 'static)>`
found struct `std::sync::Arc<dyn AB>`
error[E0308]: mismatched types
--> src/lib.rs:29:11
|
29 | use_b(x);
| ^ expected trait `B`, found trait `AB`
|
= note: expected struct `std::sync::Arc<(dyn B + 'static)>`
found struct `std::sync::Arc<dyn AB>`
The functionality provided by the traits is identical in behavior, however the context is completely disjoint so making consumers accept Arc<dyn AB> would be wrong and adding a dependency that doesn't really exist (and having to resolve naming conflicts as the names of the methods are the same in both traits.)
Is there a way to return a trait object implementing multiple traits and pass that object as parameter to function expecting the individual trait objects wrapped in Arc?
This question already has answers here:
Impl Add for type alias tuple (f64, f64)
(1 answer)
How do I implement a trait I don't own for a type I don't own?
(3 answers)
Closed 3 years ago.
I hope to implement the function for type OpResource.
type OpResource = Object<OC, Status>;
impl OpResource {
pub fn get_parameter_values(&self) -> Vec<ParameterValue> {
self.spec
.parameter_values
.clone()
.or_else(|| Some(vec![]))
.unwrap()
}
}
Then I got an error
error[E0116]: cannot define inherent `impl` for a type outside of the crate where the type is defined
|
35 | / impl OpResource {
36 | | pub fn get_parameter_values(&self) -> Vec<ParameterValue> {
37 | | self.spec
38 | | .parameter_values
... |
42 | | }
43 | | }
| |_^ impl for type defined outside of crate.
|
= note: define and implement a trait or new type instead
I can't understand where am I wrong, I just implement the function below the type, why it said I'm out of crate?
I have a trait Foo. I want to force implementors to define a method, if those implementors implement another trait (Clone in this example). My idea (Playground):
trait Foo {
// Note: in my real application, the trait has other methods as well,
// so I can't simply add `Clone` as super trait
fn foo(&self)
where
Self: Clone;
}
struct NoClone;
impl Foo for NoClone {}
Sadly, this leads to:
error[E0046]: not all trait items implemented, missing: `foo`
--> src/lib.rs:8:1
|
2 | / fn foo(&self)
3 | | where
4 | | Self: Clone;
| |____________________- `foo` from trait
...
8 | impl Foo for NoClone {}
| ^^^^^^^^^^^^^^^^^^^^ missing `foo` in implementation
I don't understand this error: the compiler clearly knows that NoClone does not implement Clone, so why am I required to provide a definitoin for foo? In particular, if I attempt to provide a definition (Playground):
impl Foo for NoClone {
fn foo(&self)
where
Self: Clone
{
unreachable!()
}
}
I get the error:
error[E0277]: the trait bound `NoClone: std::clone::Clone` is not satisfied
--> src/lib.rs:9:5
|
9 | / fn foo(&self)
10 | | where
11 | | Self: Clone
12 | | {
13 | | unreachable!()
14 | | }
| |_____^ the trait `std::clone::Clone` is not implemented for `NoClone`
|
= help: see issue #48214
= help: add #![feature(trivial_bounds)] to the crate attributes to enable
So the compiler knows for sure. (FYI: with #![feature(trivial_bounds)] it compiles, but I don't want to define a bunch of methods with unreachable!() as body.)
Why does the compiler force me to provide the method definition? Can I work around this problem somehow?
All implementors of a trait need to implement all methods that don't have a default implementation. It's the point of a trait that it has a defined interface. Adding trait bounds to a method does not change anything about this rule.
This is what the language reference says on the topic:
A trait implementation must define all non-default associated items declared by the implemented trait, may redefine default associated items defined by the implemented trait, and cannot define any other items.
This also means that a trait bound on Self in a method declaration on a trait is functionally equivalent to declaring a supertrait, except that the trait can only be used in the method that declares the bound.
The obvious work-around is to define a separate trait for the methods that have additional requirements on Self:
trait FooExt: Foo + Clone {
fn foo(&self);
}
You can now implement Foo for all types, and FooExt in addition for the types that are Clone.
Updated as requested in the comments: There is a GitHub issue discussing whether it should be allowed to implement methods with unsatisfiable trait bounds without the method body, so at least the { unimplemted()! } part could be dropped. As of April 2019, this discussion has not come to any conclusion yet, and not even the exact syntax for implementing the uncallable methods has been settled.