如何将一个不透明的值像烫手山芋一样从一个 Enum 构造函数移动到下一个枚举构造函数?

问题描述 投票:0回答:1

我想将以下

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
的所有分支都只是移动了?

rust lifetime borrow-checker linear-types
1个回答
0
投票

正如评论中所解释的,仅仅移出唯一引用并使其处于未定义状态是可以的。但是,由于您有一个不需要

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,
    }
}

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.