I'm trying to extend the Iterator trait with a custom function:
pub trait CustomTrait<T> : Iterator<Item=T> where Self: Sized, Self: 'static {
#[inline]
fn custom_function(self) -> Result<Box<dyn Iterator>, Err> {
let boxed = Box::new(self);
do_something(boxed)
}
}
It's compiles correctly. However, when I go to call my new trait on a iterator, the compiler complains about it not being implemented for the iterator. (I have tried std::ops::Range and std::slice::Iter<'_, {integer}>.)
I was able to get each function call working for individual struct types with lines such as below:
impl CustomTrait<u64> for std::ops::Range<u64> {}
However, I assume there must be a way that I can get my trait definition to apply to all Iterables without having to manually implement it for each struct that implements the Iterable trait.
When you extend a trait, you basically create a new trait that also guarantees that it has all the methods defined by the trait it's extending.
What it not does is automatically implement any of those methods for the trait you're extending.
In addition to what you already did, you actually need to implement your trait for Iterator:
impl<T> CustomTrait<T> for Iterator<Item=T> {
...
}
Related
I want trait implementations in Rust to be able to return arbitrary iterators (of specific item type) that may reference the original object with a lifetime 'a without having to explicitly mention 'a in the trait generics and everywhere where the trait is used or otherwise introducing significant trait bound bloat to user code. The only simple way I've figured to do this is that the trait has to be implemented for &'a MyStruct instead of MyStruct (this approach is used in some places in the standard library), but the significant drawback is that in generic code wrappers cannot “own” implementations of the trait (MyStruct) without exposing the lifetime in trait bounds all over the code. So nothing gained when ownership is needed.
Another way I figured out that should work (just done the simple test below so far) is to use higher-ranked lifetime bounds on a “base trait” that would implement the iterator-generation functions. In the code below Foo is the main trait, FooInterfaceGen is the iterator-generator trait that has its lifetime “hidden” through for <'a> when assumed as a super-trait of Foo. The FooInterface generated by FooInterfaceGen would be the trait for an appropriate type of iterator when modified to that application of the idea. However, it seems impossible to make additional trait bounds on the specific implementation FooInterfaceGen::Interface. The code below works, but when you uncomment the Asdf trait bound in the function footest, the compiler complains that
the trait `for<'a> Asdf` is not implemented for `<_ as FooInterfaceGen<'a>>::Interface
But I have implemented Asdf! It's as if the compiler is ignoring the 'a in the expression <T as FooInterfaceGen<'a>> and just applying for<'a> to the right-hand-side. Any ideas if this is a compiler bug, a known restriction, or of any ways around it?
trait FooInterface<'a> {
fn foo(&self) -> u32;
}
trait FooInterfaceGen<'a> {
type Interface : FooInterface<'a>;
fn gen(&'a self) -> Self::Interface;
}
trait Foo : for<'a> FooInterfaceGen<'a> { }
struct S2;
struct S1(S2);
impl<'a> FooInterfaceGen<'a> for S1 {
type Interface = &'a S2;
fn gen(&'a self) -> Self::Interface { &self.0 }
}
impl Foo for S1 { }
impl<'a> FooInterface<'a> for &'a S2 {
fn foo(&self) -> u32 { 42 }
}
trait Asdf {}
impl<'a> Asdf for &'a S2 {}
fn footest<T : Foo>(a : &T) -> u32
/* where for<'a> <T as FooInterfaceGen<'a>>::Interface : Asdf */ {
a.gen().foo()
}
fn main() {
let q = S1(S2);
println!("{}", footest(&q));
}
(Regarding some alternative implementations, maybe there's a technical reason for it, but otherwise I really don't understand the reason behind the significant trait bound bloat that Rust code easily introduces. Assuming a trait should in any reasonable situation automatically assume all the trait bound as well, also in generic code, not just specific code, without having to copy-paste an increasing number of where-clauses all over the code.)
The error seems to be a known compiler bug: https://github.com/rust-lang/rust/issues/89196
I have a trait which has a function that should return an iterator of a different trait. I also need a common function which takes this trait and does operations on it.
This is the code I have currenty:
pub trait NodeLike : Sized {
/// Get the node id
fn get_id(&self) -> i32;
}
pub trait EdgeLike {
/// Get the destination node id
fn get_node_id(&self) -> i32;
/// Get the edge id
fn get_edge_id(&self) -> i32;
/// iterates of the source nodes
fn iter_source_nodes(&self) -> dyn Iterator<Item = dyn NodeLike>;
^^^^^^^^^^^^^
}
fn operation(id: i32, edge: dyn EdgeLike) {
for node in edge.iter_source_nodes().find(|n| n.get_id() == id) {
}
}
The underlined part above throws the compiler error:
the trait `NodeLike` cannot be made into an object
`NodeLike` cannot be made into an object rustc E0038
main.rs(1, 22): for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
Reading through the documentation, I believe my NodeLike trait is object-safe. The only function it has is &Self (i.e. &self)
Now, I can further my code by removing the Sized trait on NodeLike. However, then the error occurs in the function operation; I cannot use the find function on the iterator.
How can I change my code so that I can make NodeLike object safe, AND be able to return an iterator which I can call find on?
Following Stargateur's suggestion and your playground link, I got it to compile like this:
Playground link
This is if you do not want to use any unstable features.
The trick is to specify the explicit type of the iterator. If you don't know that type, just put any stupid type in and let the compiler complain about the type mismatch. It'll tell you that we're dealing here with a slice iter, so hence the std::slice::Iter.
The other modifications are then about adding a lifetime parameter to your struct, because iter() returns references. If you don't want that, change it to into_iter, but then you must use self instead of &self.
Also, for your operation, you must do some lifetime magic...
fn operation<'a, Item: NodeLike>(id: i32, edge: &'a impl EdgeLike<'a, Item=Item> )
If you are okay with unstable features, you can avoid having to specify the exact type of the iter: In your playground version just change the dyn to impl. The compiler will tell you that that's an unstable feature and will show you the macro to use.
Finally, to avoid having to add lifetime annotations to the trait itself, there's something about generic associated types, but maybe that's going too far for now.
I'm having some dificulty wrapping my head around downcasting.
I have a struct which contains a Boxed trait, for example:
struct MyContainer {
reader: Box<dyn std::io::Read>,
}
How could I downcast the reader to my known type?
Here is a minimal example of what I'm trying to do:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2015&gist=14b44be2412342d851d3c83fd9e080b0
Normally, I'd create a as_any(&self) on the trait which would result in a &dyn Any but this is a foreign trait which I do not own.
Define your own trait which has both Any and Read as supertraits, then use that as the dyn type.
trait DowncastableRead: Read + Any {
fn as_any(&self) -> &dyn Any;
}
impl<T: Read + Any> DowncastableRead for T {
fn as_any(&self) -> &dyn Any {
self
}
}
struct MyContainer {
reader: Box<dyn DowncastableRead>,
}
With these changes, your desired code will run.
There's no way to avoid defining your own trait, because dyn requires specifying exactly one non-auto trait (carries one vtable pointer), to get the functionality of Read and the functionality of Any, you need to define a trait that combines them (and defines a vtable that supports both sets of methods).
There are 2 ways to provide methods for a Trait itself, Rustdoc distinguishes them by saying "provided methods" and impl dyn XXX. For example:
trait Trait {
fn foo(&self) {
println!("Default implementation");
}
}
impl Trait {
fn bar(&self) {
println!("Anonymous implementation?");
}
}
I noticed it when I was reading the documentation of Rust's failure crate.
What are the use cases for them? What are the differences?
The first snippet,
trait Trait {
fn foo(&self) {
println!("Default implementation");
}
}
implements a provided method on the trait. This method can be overridden by a trait implementation, but it does not have to be overridden.
The second snippet,
impl Trait {
fn bar(&self) {
println!("Anonymous implementation?");
}
}
implements an inherent method on a trait object of type dyn Trait. Method implementations for dyn Trait can only be called for trait objects, e.g. of type &dyn Trait. They can't receive self by value, since dyn Trait does not have a size known at compile time, and they can't be called on concrete types implementing Trait (including generic types with a Trait bound).
The modern notation is to write impl dyn Trait instead of impl Trait, and in fact this notation was one of the motivating examples for the introduction of the dyn keyword – the old syntax did not provide any clues as to what the semantics are, whereas the new syntax with the dyn keyword hints at the fact that this impl is only used together with dynamic dispatch.
A trait object is a fat pointer to an object implementing Trait, but the concrete type of the object is not necessarily known at compile time. The fat pointer contains a pointer to the object data, as well as a pointer to the virtual method table of the object type. The latter is used to dynamically dispatch to the correct trait implementation at runtime.
It is rather uncommon to use impl dyn Trait. Generally it's only useful if you want to make use of some dynamic type information, like downcasting to the actual type. The only traits with inherent methods on trait objects in the standard library are Any and Error.
In short: one can be overridden, and the other cannot.
When you define a trait, you define items that implementations of the trait may (or have to) override:
trait Trait {
fn foo(&self) {
println!("Default implementation");
}
}
impl Trait for i64 {
fn foo(&self) {
println!("i64 implementation: {}", self);
}
}
On the other hand, using impl Trait, you define inherent methods, which cannot be overridden:
impl Trait {
fn bar(&self) {
self.foo();
self.foo()
}
}
// Try:
impl Trait for i64 {
fn bar(&self) { ... } // error: bar cannot be overridden.
}
As a result, inherent traits methods act as the Template Method Pattern: they provide a canvas linking together one or multiple overridable method(s).
If you look at the failure crate that you linked, the method Failure::find_root_cause() states:
This is equivalent to iterating over iter_causes() and taking the last item.
You may consider those inherent methods to be convenience methods, methods providing an easy/intuitive interface for common tasks which can be accomplished manually... but are conveniently pre-defined.
Note: any inherent method could be implemented as a free function taking the trait as a first argument; however free functions cannot be called in method position.
I have a trait which only has one requirement, the presence of a methods len(&self) -> usize. It then provides implementations for a couple of new methods for the struct.
trait MyTrait {
fn len(&self) -> usize;
// ... some new functions with implementations
}
I'd like to implement this trait on std::collections::LinkedList which already has a method with that exact type signature. Currently, I'm doing this:
impl<T> MyTrait for LinkedList<T> {
fn len(&self) -> usize {
self.len()
}
}
I can then use the new methods defined by MyTrait on my LinkedList instances. However, it feels unnecessary to have to repeat the definition of the method like this, since the type signatures are identical. Is there a way to omit the re-definition of len in my trait implementation?
Is there a way to omit the re-definition of len in my trait implementation?
No, it is not possible.
You may be able to write a macro of some kind to write the code for you, but dealing with type parameters is annoying, to say the least.
See also:
How to call a method when a trait and struct use the same name?