Rust中AntLR ErrorListener所有权转移后复用问题求助
解决AntLR Rust中ErrorListener所有权转移后无法获取错误的问题
核心思路是将错误存储与Listener逻辑分离,利用Rust的共享所有权工具(Rc<RefCell<T>>)让外部仍能访问收集到的错误,即使Listener的所有权被转移给parser。
具体实现步骤
- 调整自定义ErrorListener的结构
让Listener持有一个指向共享错误集合的引用计数指针,这样即使Listener被Boxed转移,外部的指针仍能访问错误数据:
use antlr_rust::error_listener::{ErrorListener, SyntaxError}; use antlr_rust::token::Token; use std::cell::RefCell; use std::rc::Rc; // 替换成你实际的错误令牌类型 #[derive(Debug)] struct ErrorToken { line: usize, char_pos: usize, message: String, } struct MyErrorListener { errors: Rc<RefCell<Vec<ErrorToken>>>, } impl MyErrorListener { // 接收共享错误集合的克隆作为参数 fn new(errors: Rc<RefCell<Vec<ErrorToken>>>) -> Self { Self { errors } } } impl<'input, Token: Token> ErrorListener<'input, Token> for MyErrorListener { fn syntax_error( &mut self, _recognizer: &dyn antlr_rust::Recognizer<'input, Token>, _offending_symbol: Option<&Token>, line: usize, char_position_in_line: usize, msg: &str, _e: Option<&antlr_rust::error::Error>, ) { // 向共享集合中添加错误 self.errors.borrow_mut().push(ErrorToken { line, char_pos: char_position_in_line, message: msg.to_string(), }); } }
- 使用Listener并获取错误
创建共享错误集合,将其克隆传给Listener,解析完成后直接从外部的集合中读取错误:
// 创建共享的错误存储容器 let errors = Rc::new(RefCell::new(Vec::new())); // 创建Listener,传入错误容器的克隆 let listener = MyErrorListener::new(Rc::clone(&errors)); // 将Listener包装成Box并传给parser(所有权转移) parser.add_error_listener(Box::new(listener)); // 执行解析逻辑 let res = parser.query(); // 解析完成后,访问收集到的错误 let collected_errors = errors.borrow().clone(); // 或者直接遍历使用: for err in errors.borrow().iter() { println!("语法错误:第{}行,第{}列 - {}", err.line, err.char_pos, err.message); }
关于复用Listener实例的说明
由于add_error_listener接收的是Box<dyn ErrorListener>,Listener的所有权会被完全转移给parser,原Listener实例无法再直接复用。但通过上述方案,你可以:
- 复用错误存储容器:创建新的Listener实例,传入同一个
Rc<RefCell<Vec<ErrorToken>>>(注意解析前要清空容器) - 复用Listener逻辑:只要基于共享错误容器创建新的Listener实例即可,无需修改核心逻辑
如果是多线程场景,只需将Rc<RefCell<T>>替换为Arc<Mutex<T>>,保证线程安全。
内容的提问来源于stack exchange,提问作者Pierpaolo Follia
相关产品推荐
相关产品推荐

