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 (ie &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:
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.