借用可以委派的解析器的检查器问题

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

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

Parsers从Reader(可变)得到他们的输入。我希望一次只能解析一个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:包含代码示例中的注释建议和错误。

delegates rust pattern-matching borrow-checker ownership
1个回答
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
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.