我想将以下
Padded
类型输入迭代器转换器:
enum Step<T> {
Before(T),
During(T),
After
}
struct Padded<T> {
step: Step<T>
}
(请注意,在我的实际代码中,
Step
内除了Padded
之外还有其他东西,因此从struct
到enum
有额外的间接层。)
这个想法是,在每次迭代中,我们总是更改我们的
Step
,因此将存储在其中的 T
移动到下一个 Step
的构造函数中应该是正确的。但是,我无法让它工作。
简单版本:
impl<T: Iterator> Iterator for Padded<T> {
type Item = Option<T::Item>;
fn next(&mut self) -> Option<Self::Item> {
match &self.step {
Step::Before(start) => {
self.step = Step::During(*start);
Some(None)
},
Step::During(ref mut iter) => {
match iter.next() {
Some(x) => { self.step = Step::During(*iter); Some(Some(x)) },
None => { self.step = Step::After; Some(None) },
}
},
Step::After => {
None
}
}
}
}
此操作失败:
error[E0507]: cannot move out of `*start` which is behind a shared reference
--> src/lcd.rs:39:42
|
39 | self.step = Step::During(*start);
| ^^^^^^ move occurs because `*start` has type `T`, which does not implement the `Copy` trait
error[E0596]: cannot borrow data in a `&` reference as mutable
--> src/lcd.rs:42:26
|
42 | Step::During(ref mut iter) => {
| ^^^^^^^^^^^^ cannot borrow as mutable
error[E0507]: cannot move out of `*iter` which is behind a mutable reference
--> src/lcd.rs:44:59
|
44 | Some(x) => { self.step = Step::During(*iter); Some(Some(x)) },
| ^^^^^ move occurs because `*iter` has type `T`, which does not implement the `Copy` trait
我尝试通过将第三个分支更改为:
来更明显地表明
self.step
对于这个世界来说并不长
Step::After => {
self.step = Step::After;
None
}
但这并没有改变任何事情。
然后我想我应该更明确地说明这里发生的事情:
impl<T: Iterator> Padded<T> {
fn next_self_and_item(self) -> (Self, Option<Option<T::Item>>) {
match self.step {
Step::Before(start) => {
(Padded{ step: Step::During(start) }, Some(None))
},
Step::During(mut iter) => {
match iter.next() {
Some(x) => (Padded{ step: Step::During(iter) }, Some(Some(x))),
None => (Padded{ step: Step::After }, Some(None)),
}
},
Step::After => {
(Padded{ step: Step::After }, None)
}
}
}
}
这个确实通过了借用检查器,但不能用于实现
Iterator::next
:
impl<T: Iterator> Iterator for Padded<T> {
type Item = Option<T::Item>;
fn next(&mut self) -> Option<Self::Item> {
let (new_self, item) = self.next_self_and_item();
*self = new_self;
item
}
}
error[E0507]: cannot move out of `*self` which is behind a mutable reference
--> src/lcd.rs:79:32
|
79 | let (new_self, item) = self.next_self_and_item();
| ^^^^ -------------------- `*self` moved due to this method call
| |
| move occurs because `*self` has type `Padded<T>`, which does not implement the `Copy` trait
|
note: `Padded::<T>::next_self_and_item` takes ownership of the receiver `self`, which moves `*self`
--> src/lcd.rs:57:27
|
57 | fn next_self_and_item(self) -> (Self, Option<Option<T::Item>>) {
| ^^^^
那么我能做什么呢?另外,我是否正确地认为,至少在道德上,我想做的事情应该没问题,因为
self
是一个可变的参考(所以我应该能够做任何我想做的事情self.step
),并且在T
内的self.step
的所有分支都只是移动了?
正如评论中所解释的,仅仅移出唯一引用并使其处于未定义状态是不可以的。但是,由于您有一个不需要
T
的枚举变体,在这种特殊情况下,您可以使用 std::mem::replace()
获得“烫手山芋”:
fn next(&mut self) -> Option<Self::Item> {
match std::mem::replace(&mut self.step, Step::After) {
Step::Before(start) => {
self.step = Step::During(start);
Some(None)
}
Step::During(mut iter) => match iter.next() {
Some(x) => {
self.step = Step::During(iter);
Some(Some(x))
}
None => Some(None),
},
Step::After => None,
}
}