简体   繁体   English

在另一个特征上添加一个特征的迭代器

[英]Adding an iterator of a trait on another trait

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. NodeLike文档,我相信我的NodeLike特性是对象安全的。 The only function it has is &Self (ie &self)它唯一的功能是&Self (ie &self)

Now, I can further my code by removing the Sized trait on NodeLike .现在,我可以通过删除NodeLike上的Sized特征来进一步我的代码。 However, then the error occurs in the function operation ;但是,然后在函数operation出现错误; I cannot use the find function on the iterator.我无法在迭代器上使用find函数。

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?如何更改我的代码以便我可以使NodeLike对象安全,并且能够返回一个迭代器,我可以在其上调用find

Following Stargateur's suggestion and your playground link, I got it to compile like this:按照 Stargateur 的建议和你的游乐场链接,我得到了这样的编译:

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 .它会告诉你我们在这里处理的是切片迭代器,因此是std::slice::Iter

The other modifications are then about adding a lifetime parameter to your struct, because iter() returns references.其他修改是关于向结构添加生命周期参数,因为iter()返回引用。 If you don't want that, change it to into_iter , but then you must use self instead of &self .如果您不希望那样,请将其更改为into_iter ,但是您必须使用self而不是&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 .如果您对不稳定的功能没问题,则可以避免指定迭代器的确切类型:在您的操场版本中,只需将dyn更改为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.最后,为了避免必须向 trait 本身添加生命周期注释,有一些关于泛型关联类型的东西,但现在也许这太过分了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM