[英]Adding an iterator of a trait on another trait
我有一个特征,它有一个函数应该返回一个不同特征的迭代器。 我还需要一个通用函数,它接受这个特征并对其进行操作。
这是我当前的代码:
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 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>
NodeLike
文档,我相信我的NodeLike
特性是对象安全的。 它唯一的功能是&Self (ie &self)
现在,我可以通过删除NodeLike
上的Sized
特征来进一步我的代码。 但是,然后在函数operation
出现错误; 我无法在迭代器上使用find
函数。
如何更改我的代码以便我可以使NodeLike
对象安全,并且能够返回一个迭代器,我可以在其上调用find
?
按照 Stargateur 的建议和你的游乐场链接,我得到了这样的编译:
这是如果您不想使用任何不稳定的功能。
诀窍是指定迭代器的显式类型。 如果您不知道该类型,只需放入任何愚蠢的类型并让编译器抱怨类型不匹配。 它会告诉你我们在这里处理的是切片迭代器,因此是std::slice::Iter
。
其他修改是关于向结构添加生命周期参数,因为iter()
返回引用。 如果您不希望那样,请将其更改为into_iter
,但是您必须使用self
而不是&self
。
还有,为了你的手术,你必须做一些终生的魔法……
fn operation<'a, Item: NodeLike>(id: i32, edge: &'a impl EdgeLike<'a, Item=Item> )
如果您对不稳定的功能没问题,则可以避免指定迭代器的确切类型:在您的操场版本中,只需将dyn
更改为impl
。 编译器会告诉您这是一个不稳定的功能,并会向您显示要使用的宏。
最后,为了避免必须向 trait 本身添加生命周期注释,有一些关于泛型关联类型的东西,但现在也许这太过分了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.