Rust中match语句内表达式值被移动的问题及优化建议
解决Rust中Polars Expr的所有权移动问题
我正在从字符串生成Polars的Expr表达式,现有一个包含close列的DataFrame,需要实现当函数接收字符串"rolling_mean"时,并行计算close - close.rolling_mean(指定窗口)。我定义了close_column = Expr::Column(Arc::from("close"))来避免重复代码,但在match语句中,第一次引用close_column会触发值移动,导致第二个计算项无法再使用它。虽然克隆close_column能解决问题,但不确定这是不是最优方案。
原代码如下:
pub fn generate_expr_from_str(function_name: &str, window: usize) -> Expr { let close_column = Expr::Column(Arc::from("close")); let expression = match function_name { "rolling" => (close_column - close_column.rolling_mean(RollingOptions { window_size: Duration::new(window as i64), min_periods: 1 as usize, weights: None, center: true, by: None, closed_window: None, })) .alias(format!("rolling_{window}").as_str()), _ => panic!("function not implemented"), }; expression }
优化方案
因为你用的Arc本身就是原子引用计数的智能指针,克隆它的开销非常小(只是增加引用计数,不会复制底层数据),所以直接克隆是完全合理的最优方案。这里提供两种更简洁的写法:
- 提前克隆副本
在使用前先克隆出一个独立副本,原变量和副本可分别用于两个计算项:
pub fn generate_expr_from_str(function_name: &str, window: usize) -> Expr { let close_column = Expr::Column(Arc::from("close")); let close_clone = close_column.clone(); let expression = match function_name { "rolling" => (close_column - close_clone.rolling_mean(RollingOptions { window_size: Duration::new(window as i64), min_periods: 1, weights: None, center: true, by: None, closed_window: None, })) .alias(&format!("rolling_{window}")), _ => panic!("function not implemented"), }; expression }
- 使用时直接克隆
无需额外变量,直接在调用rolling_mean时克隆原变量:
pub fn generate_expr_from_str(function_name: &str, window: usize) -> Expr { let close_column = Expr::Column(Arc::from("close")); let expression = match function_name { "rolling" => (close_column - close_column.clone().rolling_mean(RollingOptions { window_size: Duration::new(window as i64), min_periods: 1, weights: None, center: true, by: None, closed_window: None, })) .alias(&format!("rolling_{window}")), _ => panic!("function not implemented"), }; expression }
另外注意:原代码中format!("rolling_{window}").as_str()存在临时字符串生命周期风险,改成&format!("rolling_{window}")更安全——alias方法接受&str类型,当前作用域内的format!返回值足够支撑这个引用的生命周期。
为什么克隆是最优解?
Arc的设计目标就是支持低成本的共享访问,克隆操作仅会原子性地增加引用计数,完全没有内存拷贝开销。相比重复创建Expr::Column(Arc::from("close"))(会生成多个指向同一字符串的独立Arc实例),克隆复用同一个Arc的引用,反而能让后续的引用计数管理更高效。
内容的提问来源于stack exchange,提问作者Sigi
相关产品推荐
相关产品推荐

