借用可以委托

时间:2018-05-25 18:32:19

标签: delegates rust pattern-matching borrow-checker ownership

我有几个解析器。有一个顶级的可以委托给另一个。

ParserReader(可变)获取输入。我希望一次只能解析一个Parser,只有一个解析器应该有Reader

我是通过为顶级解析器创建枚举来实现的,该解析器是读者或委托解析器(具有读取器)。这样它只能在没有委托时读取,这就是我想要的。

从顶级解析器,我需要可变地借用这个枚举来确定要做什么以及获取读者或委托解析器。问题是如果我想开始或停止委托,我需要移动Reader。但是在这一点上它仍然可以借用。

我创建了一个最小的例子,我已经包含了关于replace和非词汇生命期的评论中的建议:

#![feature(nll)]
use std::mem::replace;

struct Reader {
    i: u8,
}
impl Reader {
    fn next(&mut self) -> u8 {
        /* some logic here */
        self.i += 1;
        self.i
    }
}

trait Parser {
    fn parse(&mut self) -> u8;
}

enum ReaderOrDelegate {
    Read(Reader),
    Delegate(AnotherParser),  /* Trait object in reality, but keeping it simple here. */
}

struct OneParser {
    reader_or_delegate: ReaderOrDelegate,
}
impl Parser for OneParser {
    fn parse(&mut self) -> u8 {
        match self.reader_or_delegate {
            ReaderOrDelegate::Delegate(ref mut delegate) => {
                match delegate.parse() {
                    0 => {
                        replace(&mut self.reader_or_delegate, ReaderOrDelegate::Read(delegate.consume()));
                        self.parse()
                    },
                    x => 2 * x
                }
            },
            ReaderOrDelegate::Read(ref mut reader) => {
                match reader.next() {
                    0 => {
                        replace(&mut self.reader_or_delegate, ReaderOrDelegate::Delegate(AnotherParser { reader }));
                        self.parse()
                    },
                    x => 3 * x
                }
            },
        }
    }
}

struct AnotherParser {
    reader: Reader,
}
impl AnotherParser {
    fn consume(self) -> Reader {
        self.reader
    }
}
impl Parser for AnotherParser {
    fn parse(&mut self) -> u8 {
        self.reader.next() * 2
    }
}

根据评论建议,仍然存在一个错误:

error[E0308]: mismatched types
  --> src/main.rs:42:106
   |
42 |                         replace(&mut self.reader_or_delegate, ReaderOrDelegate::Delegate(AnotherParser { reader }));
   |                                                                                                          ^^^^^^ expected struct `Reader`, found &mut Reader
   |
   = note: expected type `Reader`
              found type `&mut Reader`

我相信我可以通过从reader中取出ReaderOrDelegate并将其作为Rc<RefCell<Parser>>>放在每个解析器中来解决此问题。但我认为在枚举中使用它更合乎逻辑:一次只能有一个解析器能够使用读者。这可能吗?

我知道错误在这种情况下是有意义的,但我觉得在高层次上,应该可以做我想做的事情。 Reader只需要一位所有者。

编辑:对我而言,replace的问题如何通过“嵌套”来应用于此案例似乎并非易事。 (reader已经由match借用,然后想要交换字段)。所以尽管可能相关,但我不知道另一个问题就足以解决这个问题了。反正不适合我。

编辑2 :包含代码示例中的评论建议和错误。

1 个答案:

答案 0 :(得分:1)

考虑一下:

replace(&mut self.reader_or_delegate, ReaderOrDelegate::Delegate(AnotherParser { reader }));

构建reader

需要anotherParser值,而非参考值
error[E0308]: mismatched types
  --> src/main.rs:42:106
   |
42 |                         replace(&mut self.reader_or_delegate, ReaderOrDelegate::Delegate(AnotherParser { reader }));
   |                                                                                                          ^^^^^^ expected struct `Reader`, found &mut Reader
   |
   = note: expected type `Reader`
              found type `&mut Reader`

但是不可能获得这样的价值。如果我们尝试:

ReaderOrDelegate::Read(reader) => {
    match reader.next() {
        0 => {
            replace(&mut self.reader_or_delegate, ReaderOrDelegate::Delegate(AnotherParser { reader }));
            self.parse()
        },
        x => 3 * x
    }
},

我们现在得到您设计的真正问题:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:39:36
   |
39 |             ReaderOrDelegate::Read(reader) => {
   |                                    ^^^^^^ cannot move out of borrowed content

parse方法借用self,这意味着此时我们无法移出所拥有的值 借来的self

另请注意,错误E0507也适用于该行:

replace(&mut self.reader_or_delegate, ReaderOrDelegate::Read(delegate.consume()));

因为consume尝试从借用的delegate移出一个值。

在你的代码中,编译器没有显示这个问题,但是如果你注释掉显然是你的例子中唯一剩下的问题,它就会出现。

我能够安排的唯一解决方案,而不会导致借用检查错误 基于使用在顶级解析器和委托解析器之间共享的引用计数器Reader来转换过多的设计。

使用Rc<Reader>您只有一个阅读器通过智能指针与您的解析器共享。

ReadOrDelegate枚举只显示了活动的解析器,没有更多的自有读者可以移动。

#![feature(nll)]
use std::rc::Rc;

struct Reader {
    i: u8,
}

impl Reader {
    fn next(&mut self) -> u8 {
        /* some logic here */
        self.i += 1;
        self.i
    }
}

trait Parser {
    fn parse(&mut self) -> u8;
}

enum ReaderOrDelegate {
    Read,
    Delegate,
}

struct OneParser {
    reader_or_delegate: ReaderOrDelegate,
    reader: Rc<Reader>,
    delegate: AnotherParser
}

impl Parser for OneParser {
    fn parse(&mut self) -> u8 {
        match self.reader_or_delegate {
            ReaderOrDelegate::Delegate => {
                match self.delegate.parse() {
                    0 => {
                        self.reader_or_delegate = ReaderOrDelegate::Read;
                        self.parse()
                    },
                    x => 2 * x
                }
            },
            ReaderOrDelegate::Read => {
                match Rc::get_mut(&mut self.reader).unwrap().next() {
                    0 => {
                        self.reader_or_delegate = ReaderOrDelegate::Delegate;
                        self.parse()
                    },
                    x => 3 * x
                }
            },
        }
    }
}

struct AnotherParser {
    reader: Rc<Reader>
}

impl Parser for AnotherParser {
    fn parse(&mut self) -> u8 {
        Rc::get_mut(&mut self.reader).unwrap().next() * 2
    }
}