创建一个迭代器并将其放入一个新的结构中而不打扰借用检查器
Create an iterator and put it into a new struct without bothering the borrow-checker
我正在尝试创建一个词法分析器,它使用 itertools::PutBack
对 String
中的字符进行迭代。我打算将 pushback 迭代器存储在一个结构中并将方法委托给它,以便我可以通过枚举对字符进行分类,然后将其传递给词法分析器核心的状态机(尚未编写)。
借款检查员对我不满意。列表底部附近的方法 ParserEventIterator::new
导致错误。我如何定义生命周期或借用以便我可以编译它?或者我应该使用什么 Rustic 数据结构设计来代替它?
最终,我希望它能实现适当的特征以成为合适的迭代器。 (Rust 的新手。在此之前,我用 28 种语言编程,但这个让我难住了。)
这是一个代码示例:
extern crate itertools;
use itertools::put_back;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
pub enum ParserEvent {
Letter(char),
Digit(char),
Other(char),
}
impl ParserEvent {
fn new(c: char) -> ParserEvent {
match c {
'a'...'z' | 'A'...'Z' => ParserEvent::Letter(c),
'0'...'9' => ParserEvent::Digit(c),
_ => ParserEvent::Other(c),
}
}
}
impl Display for ParserEvent {
fn fmt(&self, f: &mut Formatter) -> Result {
let mut _ctos = |c: char| write!(f, "{}", c.to_string());
match self {
ParserEvent::Letter(letter) => _ctos(*letter),
ParserEvent::Digit(digit) => _ctos(*digit),
ParserEvent::Other(o) => _ctos(*o),
}
}
}
// ParserEventIterator
// Elements ('e) must have lifetime longer than the iterator ('i).
pub struct ParserEventIterator<'i, 'e: 'i> {
char_iter: &'i mut itertools::PutBack<std::str::Chars<'e>>,
}
impl<'i, 'e: 'i> ParserEventIterator<'i, 'e> {
fn new(s: &'e std::string::String) -> ParserEventIterator<'i, 'e> {
// THIS NEXT LINE IS THE LINE WITH THE PROBLEM!!!
ParserEventIterator {
char_iter: &mut put_back(s.chars()),
}
}
fn put_back(&mut self, e: ParserEvent) -> () {
if let Some(c) = e.to_string().chars().next() {
self.char_iter.put_back(c);
}
}
}
impl<'i, 'e: 'i> Iterator for ParserEventIterator<'i, 'e> {
type Item = ParserEvent;
fn next(&mut self) -> Option<ParserEvent> {
match self.char_iter.next() {
Some(c) => Some(ParserEvent::new(c)),
None => None,
}
}
}
fn main() {
let mut _i = ParserEventIterator::new(&String::from("Hello World"));
}
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:43:9
|
43 | / ParserEventIterator {
44 | | char_iter: &mut put_back(s.chars()),
| | ------------------- temporary value created here
45 | | }
| |_________^ returns a value referencing data owned by the current function
好吧,编译器几乎是通过反映一个明显的问题来告诉你解决方案:你不能有一个活得不够长的借用,即借用会指向堆栈内存之后不存在的位置的功能已被破坏。
之所以会发生这种情况,是因为借用引用了一个在函数体内新创建的对象(在本例中为 itertools::struct::PutBack
实例)。这个实例在函数结束时连同对它的所有引用一起被销毁。所以编译器阻止你有一个所谓的 悬空指针 .
因此,您应该 将 PutBack
实例 PutBack
移动到您的 struct
:
而不是借用
// ...
pub struct ParserEventIterator<'e> {
char_iter: itertools::PutBack<std::str::Chars<'e>>
}
impl<'e> ParserEventIterator<'e> {
fn new(s: &'e std::string::String) -> ParserEventIterator<'e> {
ParserEventIterator { char_iter: put_back(s.chars()) }
}
// ...
}
我正在尝试创建一个词法分析器,它使用 itertools::PutBack
对 String
中的字符进行迭代。我打算将 pushback 迭代器存储在一个结构中并将方法委托给它,以便我可以通过枚举对字符进行分类,然后将其传递给词法分析器核心的状态机(尚未编写)。
借款检查员对我不满意。列表底部附近的方法 ParserEventIterator::new
导致错误。我如何定义生命周期或借用以便我可以编译它?或者我应该使用什么 Rustic 数据结构设计来代替它?
最终,我希望它能实现适当的特征以成为合适的迭代器。 (Rust 的新手。在此之前,我用 28 种语言编程,但这个让我难住了。)
这是一个代码示例:
extern crate itertools;
use itertools::put_back;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result;
pub enum ParserEvent {
Letter(char),
Digit(char),
Other(char),
}
impl ParserEvent {
fn new(c: char) -> ParserEvent {
match c {
'a'...'z' | 'A'...'Z' => ParserEvent::Letter(c),
'0'...'9' => ParserEvent::Digit(c),
_ => ParserEvent::Other(c),
}
}
}
impl Display for ParserEvent {
fn fmt(&self, f: &mut Formatter) -> Result {
let mut _ctos = |c: char| write!(f, "{}", c.to_string());
match self {
ParserEvent::Letter(letter) => _ctos(*letter),
ParserEvent::Digit(digit) => _ctos(*digit),
ParserEvent::Other(o) => _ctos(*o),
}
}
}
// ParserEventIterator
// Elements ('e) must have lifetime longer than the iterator ('i).
pub struct ParserEventIterator<'i, 'e: 'i> {
char_iter: &'i mut itertools::PutBack<std::str::Chars<'e>>,
}
impl<'i, 'e: 'i> ParserEventIterator<'i, 'e> {
fn new(s: &'e std::string::String) -> ParserEventIterator<'i, 'e> {
// THIS NEXT LINE IS THE LINE WITH THE PROBLEM!!!
ParserEventIterator {
char_iter: &mut put_back(s.chars()),
}
}
fn put_back(&mut self, e: ParserEvent) -> () {
if let Some(c) = e.to_string().chars().next() {
self.char_iter.put_back(c);
}
}
}
impl<'i, 'e: 'i> Iterator for ParserEventIterator<'i, 'e> {
type Item = ParserEvent;
fn next(&mut self) -> Option<ParserEvent> {
match self.char_iter.next() {
Some(c) => Some(ParserEvent::new(c)),
None => None,
}
}
}
fn main() {
let mut _i = ParserEventIterator::new(&String::from("Hello World"));
}
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:43:9
|
43 | / ParserEventIterator {
44 | | char_iter: &mut put_back(s.chars()),
| | ------------------- temporary value created here
45 | | }
| |_________^ returns a value referencing data owned by the current function
好吧,编译器几乎是通过反映一个明显的问题来告诉你解决方案:你不能有一个活得不够长的借用,即借用会指向堆栈内存之后不存在的位置的功能已被破坏。
之所以会发生这种情况,是因为借用引用了一个在函数体内新创建的对象(在本例中为 itertools::struct::PutBack
实例)。这个实例在函数结束时连同对它的所有引用一起被销毁。所以编译器阻止你有一个所谓的 悬空指针 .
因此,您应该 将 PutBack
实例 PutBack
移动到您的 struct
:
// ...
pub struct ParserEventIterator<'e> {
char_iter: itertools::PutBack<std::str::Chars<'e>>
}
impl<'e> ParserEventIterator<'e> {
fn new(s: &'e std::string::String) -> ParserEventIterator<'e> {
ParserEventIterator { char_iter: put_back(s.chars()) }
}
// ...
}