Vec<T>如何实现iter()方法?

10
我正在查看 Vec<T> 的代码,以了解它如何实现 iter(),因为我想为我的结构体实现迭代器。
pub struct Column<T> {
    name: String,
    vec: Vec<T>,
    ...
}

我的目标不是暴露字段并提供迭代器来对列进行循环、最大值、最小值、求和、平均值等操作。

fn test() {
    let col: Column<f32> = ...;
    let max = col.iter().max();
}

我想了解一下 Vec<T> 的迭代方式。我发现 iter()SliceExt 中被定义,但它只为 [T] 实现了,而不是 Vec<T>,所以我不知道如何从 Vec<T> 调用 iter()


有时我觉得自己在问一些超级明显的问题^^ 这确实有助于缩小我的调查范围,所以现在我会去研究 Deref!非常感谢。 - jimjampez
1个回答

13

正如fjh所说,这是由于Rust中解引用运算符的功能以及方法解析方式造成的。

Rust有一个特殊的Deref特质,允许实现它的类型的值被“解引用”以获取另一种类型,通常是自然与源类型相关联的类型。例如,像这样的实现:

impl<T> Deref for Vec<T> {
    type Target = [T];

    fn deref<'a>(&'a self) -> &'a [T] { self.as_slice() }
}

这意味着将一元运算符*应用于Vec<T>将产生[T],您需要再次借用它:
let v: Vec<u32> = vec![0; 10];
let s: &[u32] = &*v;

请注意,尽管deref()返回一个引用,但解引用运算符*返回的是Target而不是&Target——如果您不立即借用解引用的值,编译器会自动插入解引用。
这是谜题的第一部分。第二部分是如何解析方法。基本上,当您写下类似以下代码的时候:
v.iter()

编译器首先尝试在v的类型(在本例中为Vec<u32>)上找到定义的iter()方法。如果找不到这样的方法,则编译器会尝试插入适当数量的*&,以使方法调用变得有效。在本例中,它发现以下是有效的调用:
(&*v).iter()

记住,在Vec<T>上调用Deref返回的是&[T],并且切片确实有定义在它们身上的iter()方法。这也是您可以调用在常规值上采用&self的方法的方式-编译器会自动为您插入引用操作。


非常好的答案,我现在明白它是如何工作的了。我刚刚通过为Column结构实现Deref来实现iter()。 :) - jimjampez
是的,这个功能最好的一点就是它可以被任意代码使用,不仅限于标准库 :) - Vladimir Matveev
1
Deref 还允许将 &Vec<T> 强制转换为 &[T],因此这段代码可以编译通过:let s: &[u32] = &v; - bluss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接