I'm trying to define a trait that extends IntoIterator, to achieve something similar to the code bellow, but "associated type defaults are unstable" (https://github.com/rust-lang/rust/issues/29661).
Is there another way to achieve it?
pub trait MyTrait : IntoIterator{
type Item = i32;
fn foo(&self);
}
pub fn run<M: MyTrait>(my : M){
my.foo();
for a in my {
println!("{}", a);
}
}
I think what you want is this:
trait MyTrait: IntoIterator<Item = i32> {
fn foo(&self);
}
This means: everything that implements your trait also implements IntoIterator where the Item is i32. Or put differently: all implementors of MyTrait can also be turned into an iterator over i32s.
Related
Something like:
pub trait MyTrait {
// No methods defined/declared
}
impl MyTrait for MyType {
fn method_one_not_declared_neither_defined(&self) {
// body of trait method impl here
}
fn method_two_not_declared_neither_defined(&self) {
// body of trait method impl here
}
}
While the trait itself cannot be extended, you can still add behaviour to all types which implement a trait. This can be done using extension traits and blanket implementations.
trait MyTrait {}
struct MyType;
impl MyTrait for MyType {}
trait TraitExt {
fn foo(&self) {
println!("Foo");
}
}
impl<T> TraitExt for T where T: MyTrait {}
fn main() {
let t = MyType {};
t.foo();
}
Playground
This is not the same as extending MyTrait however - TraitExt must be in scope for foo to be called.
No. Only methods declared in trait definition might be implemented when implementing trait for a type. You can add this methods as normal type's methods, but not as trait's. Think of a trait as a public interface. You must implement all of trait's methods (besides those with default implementation) and cannot add anything more.
I'm new to rust and I experience difficulties to develop my personal first project.
To get the essential my code looks like this:
pub trait MyTrait {
type Out: MyTrait;
fn foo(&self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self <>;
fn foo(&self) -> Box<Self::Out> {
Box::new(self)
}
}
The error message I get is :
expected struct MyStruct<T> found reference &MyStruct<T>
I tried many things but I can't find how to return a box to self...
I have another question: actually MyTrait extends another trait and I have many struct that implement MyTrait so in my code I have many impl, one for each trait by struct and I find it really verbose, isn't it possible to implement all methods (from a trait and all its parents) at once (like in java) ? Or is there syntactic sugar to implement methods with closures ?
Thanks
Box needs to own self. You cannot pass a reference into it, it has to be the actual self object.
This works:
pub trait MyTrait {
type Out: MyTrait;
fn foo(self) -> Box<Self::Out>;
}
pub struct MyStruct<T: MyTrait>(Box<T>);
impl<T: MyTrait> MyTrait for MyStruct<T> {
type Out = Self;
fn foo(self) -> Box<Self::Out> {
Box::new(self)
}
}
Further remarks:
I'm unsure why you need that function, but it seems to me like you are trying to downcast from a boxed dyn trait to an actual type.
Sadly, this won't work this way. It's impossible for the compiler to figure out which type was the original type if your Box<dyn MyTrait> doesn't contain that information any more. That's why you need the Out associated type here, but you probably didn't yet realize that this means you can no longer store a Box<dyn MyTrait> object. It's now a Box<dyn MyTrait<Out = MyStruct>> object, which cannot be mixed with other MyTrait types any more.
If you really want to achieve that, there are several options. RTTI is one option, with the Any trait.
Another one would be a Visitor pattern, which could resolve this:
pub trait Visitor {
fn visit_mystruct(&mut self, s: &mut MyStruct);
}
pub struct MyVisitor;
impl Visitor for MyVisitor {
fn visit_mystruct(&mut self, s: &mut MyStruct) {
println!("Visited MyStruct: {:?}", s.0);
}
}
pub trait MyTrait {
fn visit(&mut self, visitor: &mut dyn Visitor);
}
pub struct MyStruct(i32);
impl MyTrait for MyStruct {
fn visit(&mut self, visitor: &mut dyn Visitor) {
visitor.visit_mystruct(self);
}
}
fn main() {
let mut obj: Box<dyn MyTrait> = Box::new(MyStruct(42)) as Box<dyn MyTrait>;
let mut visitor = MyVisitor;
// Here is no information any more about the actual type of `obj`.
// Visitor gets the type resolved again
obj.visit(&mut visitor);
}
Visited MyStruct: 42
A visitor pattern is especially useful in cases like tree structures, because it can be recursively applied to children. It is commonly used in compilers.
Another alternative would be to use an Enum instead of a Box<dyn Trait>.
Although those are all just based on assumptions now.
I remember there was a way to define a trait so that you will not need to write this:
trait A<T> {
fn f();
}
impl A<T> for T {
fn f() {}
}
As far as I can remember, it was possible to shorten the impl A<T> for T line like this:
impl A for T {
I don't recall the exact recipe of doing this. I believe there is a term related to such a shortening.
The ingredient you're looking for is Default Type Parameters, where you could make T default to Self:
trait A<T = Self> {
fn f();
}
struct Tee;
impl A for Tee { // the "A" is A<Self>, i.e. A<Tee>.
fn f() {}
}
In the standard library, the PartialEq trait is an example using this.
I'm trying to create a trait that should abstract over functions/closures with a different number of arguments. Something like this:
trait MyTrait {}
impl MyTrait for Box<Fn() -> &'static str> {}
impl MyTrait for Box<Fn(u8) -> u8> {}
Initially I planned to use it like this:
fn myf<F: MyTrait>(_fun: F) {}
fn main() {
myf(Box::new(|i: u8| i + 2))
}
But this code fails with error:
error[E0277]: the trait bound `std::boxed::Box<[closure#src/main.rs:11:18: 11:31]>: MyTrait` is not satisfied
When I cast the box like this, everything compiles correctly:
myf(Box::new(|i: u8| i + 2) as Box<Fn(_) -> _>)
Playground
Why can't the Rust compiler infer this trait without a cast? Is my approach (using cast) correct, or is there a simpler way? I prefer to enable trivial_casts warning for my projects and this syntax triggers it.
This is a thing that one tends to forget: each closure is a different struct that implements Fn: Fn is a trait, not a struct, and trait implementations are not transitive.
Here is a little example that shows this point:
trait Base {}
trait Derived {}
struct Foo {}
impl Base for Derived {}
impl Derived for Foo {}
fn myf<T>(_t: Box<T>)
where
T: Base + ?Sized,
{
}
fn main() {
let foo = Box::new(Foo {});
//myf(foo) // does not compile
myf(foo as Box<Derived>)
}
The thing you really wanted to do is:
trait MyTrait {}
impl<T> MyTrait for T
where
T: Fn() -> &'static str,
{
}
impl<T> MyTrait for T
where
T: Fn(u8) -> u8,
{
}
fn myf<F>(_fun: Box<F>)
where
F: MyTrait,
{
}
fn main() {
myf(Box::new(|i: u8| i + 2))
}
But this cannot compile because there are two conflicting implementations.
Assuming the following Rust code:
trait MyTrait {...}
struct MyStruct;
impl MyTrait for MyStruct {...}
impl MyStruct {
pub fn new() -> MyStruct { MyStruct{...} }
}
I'm able to write:
let foo: MyStruct = MyStruct::new();
However I can't
let bar: MyTrait = MyStruct::new();
Other interface-oriented programming languages can do that. Am I missing something? How can I pass various objects to a method that accepts only MyTrait? Do I need to use "templates" such as my_method<T: MyTrait>(param: T) {...}?
You don't need to define bar as a MyTrait object. (This is even the wrong thinking, because rust doesn't really have inheritance. Think of traits as more like interfaces in Java. In this case, it seems like you're treating MyTrait as a superclass of MyStruct)
You can do this
let bar = MyStruct::new();
and then just pass it in function defined like this:
fn my_method<T: MyTrait>(param: T) {...}
my_method(bar)
This works because Rust statically checks that bar, which is of type MyStruct, implements the trait MyTrait.
Side note: If you want to create a vector of trait objects, check this question.
This is because a trait may be implmented by many types and therefor the size of bar is unknown. However a reference's size would be know, so the following works.
trait MyTrait {}
struct MyStruct;
impl MyTrait for MyStruct {}
impl MyStruct {
fn new() -> Self {
MyStruct
}
}
fn main() {
let foo: MyStruct = MyStruct::new();
let bar: &MyTrait = &MyStruct::new();
}
Notice that bar isn't a MyTrait, it's a &MyTrait, this is called a trait object.