如何在Rust中避免重复实例化Regex?
解决Rust中Regex复用的所有权与借用问题(Advent of Code 2023 Day 1)
问题根源
你遇到的借用检查器报错,是因为Regex类型未实现Copy trait,直接传递Regex实例会触发所有权转移——第一次调用parse_line后,first_regex和second_regex的所有权会被移动到函数内部,后续迭代无法再使用原变量。下面是两种符合你需求的解决方案:
优先方案:通过引用传递复用Regex
这是性能最优的方案,仅传递Regex的不可变引用,全程保留原实例的所有权,实现完全复用。
修改后的代码示例:
use regex::Regex; use std::fs; fn parse_number(re: &Regex, line: &str) -> Option<i32> { // 示例:匹配第一个数字并解析 re.find(line) .and_then(|m| m.as_str().parse().ok()) } fn parse_line(first_regex: &Regex, second_regex: &Regex, line: &str) -> (i32, i32) { let first_parsed = parse_number(first_regex, line).unwrap(); let last_parsed = parse_number(second_regex, line).unwrap_or(first_parsed); (first_parsed, last_parsed) } fn day_1(path: &str) -> i32 { // 仅编译一次正则表达式 let first_regex = Regex::new(r"\d").unwrap(); // 匹配第一个数字 let second_regex = Regex::new(r"\d(?=[^\d]*$)").unwrap(); // 匹配最后一个数字 let file = fs::read_to_string(path).expect("Failed to read input file"); file.lines().fold(0, |acc, line| { let (first, last) = parse_line(&first_regex, &second_regex, line); acc + first * 10 + last }) }
核心改动:
- 将
parse_number和parse_line的参数从Regex改为&Regex,仅传递引用而非转移所有权 - 在
fold迭代中传递&first_regex和&second_regex,保证原实例可被重复借用
备选方案:克隆Regex实现复用
Regex的克隆是轻量级操作——内部仅复制指向已编译正则表达式的指针,不会重新编译,因此性能远优于每次重新初始化。
修改后的代码示例:
use regex::Regex; use std::fs; fn parse_number(re: Regex, line: &str) -> Option<i32> { re.find(line) .and_then(|m| m.as_str().parse().ok()) } fn parse_line(first_regex: Regex, second_regex: Regex, line: &str) -> (i32, i32) { let first_parsed = parse_number(first_regex, line).unwrap(); let last_parsed = parse_number(second_regex, line).unwrap_or(first_parsed); (first_parsed, last_parsed) } fn day_1(path: &str) -> i32 { let first_regex = Regex::new(r"\d").unwrap(); let second_regex = Regex::new(r"\d(?=[^\d]*$)").unwrap(); let file = fs::read_to_string(path).expect("Failed to read input file"); file.lines().fold(0, |acc, line| { // 每次迭代克隆正则实例,避免所有权转移 let (first, last) = parse_line(first_regex.clone(), second_regex.clone(), line); acc + first * 10 + last }) }
额外优化:全局缓存正则表达式
如果需要在多个函数中复用正则,可以用lazy_static或once_cell实现全局编译,避免手动传递引用:
use lazy_static::lazy_static; use regex::Regex; use std::fs; lazy_static! { static ref FIRST_REGEX: Regex = Regex::new(r"\d").unwrap(); static ref LAST_REGEX: Regex = Regex::new(r"\d(?=[^\d]*$)").unwrap(); } fn parse_number(re: &Regex, line: &str) -> Option<i32> { re.find(line) .and_then(|m| m.as_str().parse().ok()) } fn parse_line(line: &str) -> (i32, i32) { let first_parsed = parse_number(&FIRST_REGEX, line).unwrap(); let last_parsed = parse_number(&LAST_REGEX, line).unwrap_or(first_parsed); (first_parsed, last_parsed) } fn day_1(path: &str) -> i32 { let file = fs::read_to_string(path).expect("Failed to read input file"); file.lines().fold(0, |acc, line| { let (first, last) = parse_line(line); acc + first * 10 + last }) }
内容的提问来源于stack exchange,提问作者mzedeler
相关产品推荐
相关产品推荐

