Vec<T> 是如何实现 iter() 的呢?
How does Vec<T> implement iter()?
我正在查看 Vec<T>
的代码以了解它如何实现 iter()
因为我想为我的结构实现迭代器:
pub struct Column<T> {
name: String,
vec: Vec<T>,
...
}
我的目标不是公开字段并提供迭代器来为列执行循环、max、min、sum、avg 等。
fn test() {
let col: Column<f32> = ...;
let max = col.iter().max();
}
我想我会看看 Vec<T>
是如何进行迭代的。我可以看到 iter()
是在 SliceExt
中定义的,但它是为 [T]
而不是 Vec<T>
实现的,所以我很困惑如何从 [=13= 调用 iter()
]?
确实,正如 fjh 所说,这是由于 Rust 中取消引用运算符的功能以及方法的解析方式所致。
Rust 具有特殊的 Deref
特性,允许实现它的类型的值是 "dereferenced" 以获得另一种类型,通常是自然连接到源类型的类型。例如,像这样的实现:
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()
returns 是引用,取消引用运算符 *
returns Target
,而不是 &Target
-如果您不立即借用取消引用的值,编译器会插入自动取消引用。
这是第一块拼图。第二个是方法是如何解决的。基本上,当你写类似
v.iter()
编译器首先尝试查找定义在 v
类型上的 iter()
(在本例中为 Vec<u32>
)。如果找不到这样的方法,编译器会尝试插入适当数量的 *
和 &
以使方法调用有效。在这种情况下,它发现以下确实是一个有效的调用:
(&*v).iter()
请记住,Deref
在 Vec<T>
returns &[T]
上,切片上确实定义了 iter()
方法。这也是您可以调用的方式,例如在常规值上采用 &self
的方法 - 编译器会自动为您插入引用操作。
我正在查看 Vec<T>
的代码以了解它如何实现 iter()
因为我想为我的结构实现迭代器:
pub struct Column<T> {
name: String,
vec: Vec<T>,
...
}
我的目标不是公开字段并提供迭代器来为列执行循环、max、min、sum、avg 等。
fn test() {
let col: Column<f32> = ...;
let max = col.iter().max();
}
我想我会看看 Vec<T>
是如何进行迭代的。我可以看到 iter()
是在 SliceExt
中定义的,但它是为 [T]
而不是 Vec<T>
实现的,所以我很困惑如何从 [=13= 调用 iter()
]?
确实,正如 fjh 所说,这是由于 Rust 中取消引用运算符的功能以及方法的解析方式所致。
Rust 具有特殊的 Deref
特性,允许实现它的类型的值是 "dereferenced" 以获得另一种类型,通常是自然连接到源类型的类型。例如,像这样的实现:
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()
returns 是引用,取消引用运算符 *
returns Target
,而不是 &Target
-如果您不立即借用取消引用的值,编译器会插入自动取消引用。
这是第一块拼图。第二个是方法是如何解决的。基本上,当你写类似
v.iter()
编译器首先尝试查找定义在 v
类型上的 iter()
(在本例中为 Vec<u32>
)。如果找不到这样的方法,编译器会尝试插入适当数量的 *
和 &
以使方法调用有效。在这种情况下,它发现以下确实是一个有效的调用:
(&*v).iter()
请记住,Deref
在 Vec<T>
returns &[T]
上,切片上确实定义了 iter()
方法。这也是您可以调用的方式,例如在常规值上采用 &self
的方法 - 编译器会自动为您插入引用操作。