У меня есть несколько парсеров.Существует элемент верхнего уровня, который может делегировать другому.
Parser
s получают свои данные от 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
.
EDIT нужен только один владелец. Мне кажется, нетривиально, как вопрос с replace
может быть применен к этому случаю с помощью 'nesting''(reader
уже занято match
, а затем хотите поменять поле).Так что, возможно, это связано, но я не думаю, что этого достаточно, чтобы решить этот вопрос.В любом случае, не для меня.
РЕДАКТИРОВАТЬ 2 : Включены предложения комментариев в примере кода и ошибка.