我有以下
trait T {}
type Iter = fn() -> Iterator<Item = T>;
fn func(iter: Iter) {
for a in iter() {
// ...
}
}
我希望iter
返回带有移动语义的迭代器,因此我不必返回&Iterator
。问题是,Iterator
是一个特征,所以它没有被确定。上面的代码得到一个编译错误,说Iterable不满足Sized特征,因为所有局部变量都必须是静态大小。
除此之外,T
也是一种特质,因此未经过调整,因此我无法将a
绑定到它,因为它未经过调整。
我是Rust的新手,所以这真的让我感到沮丧。如何使用未分类的类型?
答案 0 :(得分:4)
你可能根本就不应该使用未经过类型化的类型。请改用泛型:
trait Foo {} // T is a common name for type parameters, so use a different name
fn func<I, F>(iter: F) where I: Iterator, I::Item: Foo, F: FnOnce() -> I {
for a in iter() {
// ...
}
}
查看generics和Fn*
traits上的书籍章节。
顺便说一下,接受一个函数看起来并不是很有用,因为你只需在开始时调用它一次。编写这样的函数似乎更简单:
fn func<I>(iter: I) where I: Iterator, I::Item: Foo {
for a in iter {
// ...
}
}
答案 1 :(得分:1)
仅限不合格类型&#34;工作&#34;如果涉及额外的间接水平。例如:
trait Ttait {}
fn foo(x: Trait) {} // error: x would be unsized which is not allowed
fn bar(x: &Trait) {} // OK: x is just a reference
fn baz(x: Box<Trait>) {} // OK: x is just an "owning pointer"
但是,您不应该使用特征作为类型,而应该更喜欢将特征用作 bounds 的特征,用于泛型函数和结构的参数:
fn generic<Type: Trait>(x: Type) {}
这实际上不是一个功能,而是一个系列的功能。对于实现Type
的每个类型Trait
,编译器将根据需要创建generic
的特殊版本。如果您具有实现x
并编写Trait
的具体类型的值generic(x)
,那么您将调用一个特别为该类型未创建的函数创建的函数。这被称为&#34;单态化&#34;。
因此,特质有两种用途。它们充当未规划类型(对于特征对象,动态分派,动态多态)以及通用代码的类型边界(静态分派,静态多态)。我的建议是尽可能避免使用特征对象,而不是通用代码。
如果不确切知道自己要做什么,请告诉我一个可能性:
trait Trait {
fn foo(&self);
}
fn func<'x,I>(iterable: I) where I: IntoIterator<Item = &'x Trait> {
for a in iterable {
a.foo();
}
}
struct Example;
impl Trait for Example {
fn foo(&self) {
println!("Example::foo()");
}
}
fn main() {
let arr = [Example, Example];
func(arr.iter().map(|x| x as &Trait));
}
这是一个演示两种特质用途的例子。 func
在它所采用的迭代类型上是通用的,但使用动态调度来调用正确的foo
函数。这可能与你想要做的最接近。
你也可以去&#34;完全通用&#34; (避免动态调度foo
来电。请参阅delnan的回答)或&#34;完全动态&#34; (使func
不知道它在运行时实际处理的迭代器类型)。有了更多的背景,我们可能会提出更好的建议。