[英]How to implement an iterator over chunks of an array in a struct?
I want to implement an iterator for the struct with an array as one of its fields.我想为结构实现一个迭代器,并将数组作为其字段之一。 The iterator should return a slice of that array, but this requires a lifetime parameter.
迭代器应该返回该数组的一个切片,但这需要一个生命周期参数。 Where should that parameter go?
那个参数 go 应该在哪里?
The Rust version is 1.37.0 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)
}
}
When you return a reference from a function, its lifetime needs to be tied to something else.当您从 function 返回引用时,它的生命周期需要与其他东西相关联。 Otherwise, the compiler wouldn't know how long the reference is valid (the exception to this is a
'static
lifetime, which lasts for the duration of the whole program).否则,编译器将不知道引用的有效时间(例外情况是
'static
生命周期”,它会持续整个程序的持续时间)。
So we need an existing reference to the slices.所以我们需要对切片的现有引用。 One standard way to do this is to tie the reference to the iterator itself.
执行此操作的一种标准方法是将引用绑定到迭代器本身。 For example,
例如,
struct Iter<'a> {
slice: &'a [u8; 100],
num: usize,
}
Then what you have works almost verbatim.然后你所拥有的几乎是逐字逐句的。 (I've changed the names of the types and fields to be a little more informative).
(我已更改类型和字段的名称以提供更多信息)。
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)
}
}
Now, you probably still have an actual [u8; 100]
现在,你可能还有一个实际的
[u8; 100]
[u8; 100]
somewhere, not just a reference. [u8; 100]
某处,而不仅仅是参考。 If you still want to work with that, what you'll want is a separate struct that has a method to convert into A
.如果您仍想使用它,您将需要一个单独的结构,该结构具有转换为
A
的方法。 For example例如
struct Data {
array: [u8; 100],
}
impl Data {
fn iter<'a>(&'a self) -> Iter<'a> {
Iter {
slice: &self.array,
num: 0,
}
}
}
Thanks to lifetime elision, the lifetimes on iter
can be left out:由于生命周期省略,可以省略
iter
上的生命周期:
impl Data {
fn iter(&self) -> Iter {
Iter {
slice: &self.array,
num: 0,
}
}
}
Just a few notes.只是一些笔记。 There was one compiler error with
[0u8; 100]
[0u8; 100]
[0u8; 100]
. [0u8; 100]
。 This may have been a typo for [u8; 100]
这可能是
[u8; 100]
[u8; 100]
, but just in case, here's why we can't do that. [u8; 100]
,但以防万一,这就是我们不能这样做的原因。 In the fields for a struct definition, only the types are specified.在结构定义的字段中,仅指定类型。 There aren't default values for the fields or anything like that.
字段或类似的东西没有默认值。 If you're trying to have a default for the struct, consider using the
Default
trait .如果您尝试为结构设置默认值,请考虑使用
Default
trait 。
Second, you're probably aware of this, but there's already an implementation of a chunk iterator for slices.其次,您可能已经意识到这一点,但是已经有一个用于切片的块迭代器的实现。 If
slice
is a slice (or can be deref coerced into a slice - vectors and arrays are prime examples), then slice.chunks(n)
is an iterator over chunks of that slice with length n
.如果
slice
是一个切片(或者可以取消引用强制转换为一个切片 - 向量和 arrays 是主要示例),那么slice.chunks(n)
是一个迭代器,该迭代器对长度为n
的切片的块进行迭代。 I gave an example of this in the code linked above.我在上面链接的代码中给出了一个例子。 Interestingly, that implementation uses a very similar idea: slice.chunks(n) returns a new struct with a lifetime parameter and implements
Iterator
.有趣的是,该实现使用了一个非常相似的想法: slice.chunks(n) 返回一个带有生命周期参数的新结构并实现
Iterator
。 This is almost exactly the same as our Data::iter
.这与我们的
Data::iter
几乎完全相同。
Finally, your implementation of next
has a bug in it that causes an out-of-bounds panic when run.最后,您的
next
实现中有一个错误,在运行时会导致越界恐慌。 See if you can spot it!看看你能不能看出来!
I wouldn't implement my own.我不会实现我自己的。 Instead, I'd reuse the existing
chunks
iterator and implement IntoIterator
for a reference to the type :相反,我会重用现有的
chunks
迭代器并实现IntoIterator
以引用类型:
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>())
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.