为可以委托的解析器借用检查器问题
Borrow checker problems for parser that can delegate
我有几个解析器。有一个顶层可以委托给另一个。
Parser
s 从 Reader
(可变)获取输入。我只希望一个 Parser
能够一次解析,只有一个解析器应该具有 Reader
.
我通过为顶级解析器创建一个枚举来做到这一点,该解析器可以是 reader,也可以是委托解析器(具有 reader)。这样它只能在未委托时读取,这就是我想要的。
从顶级解析器,我需要可变地借用这个枚举来确定要做什么并获得 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`
我相信我可以通过从 ReaderOrDelegate
中取出 reader
并将其作为 Rc<RefCell<Parser>>>
放入每个解析器来解决这个问题。但我认为将它放在枚举中更合乎逻辑:一次应该只有一个解析器能够使用 reader。这可能吗?
我知道在这种情况下错误是有道理的,但我觉得在高层次上,应该可以做我想做的事。 Reader
.
只需要一个所有者
编辑:对我来说,replace
的问题如何应用到 'nesting' 的情况下似乎很重要(reader
已经被 match
借用了,然后想交换一个字段)。因此,虽然可能相关,但我认为另一个问题不足以解决这个问题。反正不适合我。
编辑 2:在代码示例和错误中包含注释建议。
考虑以下行:
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>
您只有一个 reader 通过智能指针与您的解析器共享。
ReadOrDelegate
enum 仅指示活动解析器,不再拥有 reader 移动。
#![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
}
}
我有几个解析器。有一个顶层可以委托给另一个。
Parser
s 从 Reader
(可变)获取输入。我只希望一个 Parser
能够一次解析,只有一个解析器应该具有 Reader
.
我通过为顶级解析器创建一个枚举来做到这一点,该解析器可以是 reader,也可以是委托解析器(具有 reader)。这样它只能在未委托时读取,这就是我想要的。
从顶级解析器,我需要可变地借用这个枚举来确定要做什么并获得 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`
我相信我可以通过从 ReaderOrDelegate
中取出 reader
并将其作为 Rc<RefCell<Parser>>>
放入每个解析器来解决这个问题。但我认为将它放在枚举中更合乎逻辑:一次应该只有一个解析器能够使用 reader。这可能吗?
我知道在这种情况下错误是有道理的,但我觉得在高层次上,应该可以做我想做的事。 Reader
.
编辑:对我来说,replace
的问题如何应用到 'nesting' 的情况下似乎很重要(reader
已经被 match
借用了,然后想交换一个字段)。因此,虽然可能相关,但我认为另一个问题不足以解决这个问题。反正不适合我。
编辑 2:在代码示例和错误中包含注释建议。
考虑以下行:
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>
您只有一个 reader 通过智能指针与您的解析器共享。
ReadOrDelegate
enum 仅指示活动解析器,不再拥有 reader 移动。
#![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
}
}