You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中AntLR ErrorListener所有权转移后复用问题求助

解决AntLR Rust中ErrorListener所有权转移后无法获取错误的问题

核心思路是将错误存储与Listener逻辑分离,利用Rust的共享所有权工具(Rc<RefCell<T>>)让外部仍能访问收集到的错误,即使Listener的所有权被转移给parser。

具体实现步骤

  1. 调整自定义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(),
        });
    }
}
  1. 使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:42:25