如何在结构中的数组块上实现迭代器?
How to implement an iterator over chunks of an array in a struct?
我想为以数组作为其字段之一的结构实现迭代器。迭代器应该 return 该数组的一部分,但这需要一个生命周期参数。该参数应该去哪里?
Rust 版本为 1.37.0
struct A {
a: [u8; 100],
num: usize,
}
impl Iterator for A {
type Item = &[u8]; // this requires a lifetime parameter, but there is none declared
fn next(&mut self) -> Option<Self::Item> {
if self.num >= 10 {
return None;
}
let res = &self.a[10*self.num..10*(self.num+1)];
self.num += 1;
Some(res)
}
}
当您 return 来自函数的引用时,它的生命周期需要与其他东西绑定。否则,编译器将不知道引用的有效期有多长(例外情况是 'static
生命周期,它持续整个程序的持续时间)。
所以我们需要对切片的现有引用。执行此操作的一种标准方法是将引用绑定到迭代器本身。例如,
struct Iter<'a> {
slice: &'a [u8; 100],
num: usize,
}
那么你所拥有的几乎一字不差。 (我更改了类型和字段的名称以提供更多信息)。
impl<'a> Iterator for Iter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.num >= 100 {
return None;
}
let res = &self.slice[10 * self.num..10 * (self.num + 1)];
self.num += 1;
Some(res)
}
}
现在,您可能在某处还有实际的 [u8; 100]
,而不仅仅是参考。如果您仍然想使用它,您需要的是一个单独的结构,它有一个方法可以转换为 A
。例如
struct Data {
array: [u8; 100],
}
impl Data {
fn iter<'a>(&'a self) -> Iter<'a> {
Iter {
slice: &self.array,
num: 0,
}
}
}
感谢生命周期省略,iter
上的生命周期可以省略:
impl Data {
fn iter(&self) -> Iter {
Iter {
slice: &self.array,
num: 0,
}
}
}
只是一些注意事项。 [0u8; 100]
存在一个编译器错误。这可能是 [u8; 100]
的拼写错误,但以防万一,这就是我们不能这样做的原因。在结构定义的字段中,仅指定类型。这些字段或类似的东西没有默认值。如果您尝试为结构设置默认值,请考虑使用 Default
trait.
其次,您可能已经意识到这一点,但是已经有 an implementation 切片的块迭代器。如果 slice
是一个切片(或者可以被 deref 强制转换为一个切片 - 向量和数组是主要示例),那么 slice.chunks(n)
是该切片的长度为 n
的块的迭代器。我在上面链接的代码中给出了一个例子。有趣的是,该实现使用了一个非常相似的想法:slice.chunks(n) return 是一个带有生命周期参数的新结构并实现了 Iterator
。这和我们的Data::iter
.
几乎一模一样
最后,您的 next
实现有一个错误,当 运行 时会导致越界恐慌。看看你能不能认出来!
我不会实现我自己的。相反,我会重用现有的 chunks
iterator and :
struct A {
a: [u8; 100],
num: usize,
}
impl<'a> IntoIterator for &'a A {
type Item = &'a [u8];
type IntoIter = std::slice::Chunks<'a, u8>;
fn into_iter(self) -> Self::IntoIter {
self.a.chunks(self.num)
}
}
fn example(a: A) {
for chunk in &a {
println!("{}", chunk.iter().sum::<u8>())
}
}
我想为以数组作为其字段之一的结构实现迭代器。迭代器应该 return 该数组的一部分,但这需要一个生命周期参数。该参数应该去哪里?
Rust 版本为 1.37.0
struct A {
a: [u8; 100],
num: usize,
}
impl Iterator for A {
type Item = &[u8]; // this requires a lifetime parameter, but there is none declared
fn next(&mut self) -> Option<Self::Item> {
if self.num >= 10 {
return None;
}
let res = &self.a[10*self.num..10*(self.num+1)];
self.num += 1;
Some(res)
}
}
当您 return 来自函数的引用时,它的生命周期需要与其他东西绑定。否则,编译器将不知道引用的有效期有多长(例外情况是 'static
生命周期,它持续整个程序的持续时间)。
所以我们需要对切片的现有引用。执行此操作的一种标准方法是将引用绑定到迭代器本身。例如,
struct Iter<'a> {
slice: &'a [u8; 100],
num: usize,
}
那么你所拥有的几乎一字不差。 (我更改了类型和字段的名称以提供更多信息)。
impl<'a> Iterator for Iter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<Self::Item> {
if self.num >= 100 {
return None;
}
let res = &self.slice[10 * self.num..10 * (self.num + 1)];
self.num += 1;
Some(res)
}
}
现在,您可能在某处还有实际的 [u8; 100]
,而不仅仅是参考。如果您仍然想使用它,您需要的是一个单独的结构,它有一个方法可以转换为 A
。例如
struct Data {
array: [u8; 100],
}
impl Data {
fn iter<'a>(&'a self) -> Iter<'a> {
Iter {
slice: &self.array,
num: 0,
}
}
}
感谢生命周期省略,iter
上的生命周期可以省略:
impl Data {
fn iter(&self) -> Iter {
Iter {
slice: &self.array,
num: 0,
}
}
}
只是一些注意事项。 [0u8; 100]
存在一个编译器错误。这可能是 [u8; 100]
的拼写错误,但以防万一,这就是我们不能这样做的原因。在结构定义的字段中,仅指定类型。这些字段或类似的东西没有默认值。如果您尝试为结构设置默认值,请考虑使用 Default
trait.
其次,您可能已经意识到这一点,但是已经有 an implementation 切片的块迭代器。如果 slice
是一个切片(或者可以被 deref 强制转换为一个切片 - 向量和数组是主要示例),那么 slice.chunks(n)
是该切片的长度为 n
的块的迭代器。我在上面链接的代码中给出了一个例子。有趣的是,该实现使用了一个非常相似的想法:slice.chunks(n) return 是一个带有生命周期参数的新结构并实现了 Iterator
。这和我们的Data::iter
.
最后,您的 next
实现有一个错误,当 运行 时会导致越界恐慌。看看你能不能认出来!
我不会实现我自己的。相反,我会重用现有的 chunks
iterator and
struct A {
a: [u8; 100],
num: usize,
}
impl<'a> IntoIterator for &'a A {
type Item = &'a [u8];
type IntoIter = std::slice::Chunks<'a, u8>;
fn into_iter(self) -> Self::IntoIter {
self.a.chunks(self.num)
}
}
fn example(a: A) {
for chunk in &a {
println!("{}", chunk.iter().sum::<u8>())
}
}