在Rust Polars中用自定义函数将&str转为f64的问题排查
问题解决:Polars中存储容量单位转换(Rust)
一、修复自定义函数的调用错误
你遇到的核心问题是**map方法的使用场景错误**,以及对Polars Expr API的理解偏差:
with_columns是Polars的标准方法,确保导入polars::prelude::*即可使用,它支持传入多个Expr数组;with_column仅支持单个Expr。col("value").map()用于处理整个ChunkedArray,而你需要处理单个字符串元素,应使用map_elements方法。- 避免在转换逻辑中用
unwrap,改用Result返回错误,符合Polars的错误处理机制。
修复后的完整代码:
use polars::prelude::*; pub fn convert_str_to_tb(value: &str) -> Result<f64, String> { let value = value.replace(",", ""); let mut parts = value.split_whitespace(); let num_str = parts.next().ok_or_else(|| "格式错误:缺失数字部分".to_string())?; let num = num_str.parse::<f64>().map_err(|e| format!("数字解析失败:{}", e))?; let unit = parts.next().ok_or_else(|| "格式错误:缺失单位部分".to_string())?; Ok(match unit { "KB" => num / 1_000_000_000.0, "MB" => num / 1_000_000.0, "GB" => num / 1_000.0, "TB" => num, _ => return Err(format!("不支持的单位:{}", unit)), }) } fn main() -> Result<(), Box<dyn std::error::Error>> { let mut df = df!( "volume" => &["volume01", "volume02", "volume03"], "value" => &["1,000 GB", "2,000,000 MB", "3 TB"] )?; df = df.with_columns([ col("value") .map_elements(convert_str_to_tb, GetOutput::from_type(DataType::Float64)) .alias("value_tb") ])?; println!("{}", df); Ok(()) }
二、无需自定义函数的原生DSL实现
Polars提供了丰富的字符串和条件表达式API,可完全用原生语法实现转换,还能利用向量化优化提升性能:
use polars::prelude::*; fn main() -> Result<(), Box<dyn std::error::Error>> { let mut df = df!( "volume" => &["volume01", "volume02", "volume03"], "value" => &["1,000 GB", "2,000,000 MB", "3 TB"] )?; df = df.with_columns([ // 移除逗号并按空格分割为数组 col("value") .str() .replace(",", "", false) .str() .split(" ", false) .alias("split_value"), // 提取数字部分并转为f64 col("split_value") .arr() .get(0) .str() .parse::<f64>() .alias("num"), // 提取单位部分 col("split_value") .arr() .get(1) .alias("unit"), // 根据单位计算TB值 when(col("unit") == "KB") .then(col("num") / 1_000_000_000.0) .when(col("unit") == "MB") .then(col("num") / 1_000_000.0) .when(col("unit") == "GB") .then(col("num") / 1_000.0) .when(col("unit") == "TB") .then(col("num")) .otherwise(lit(f64::NAN)) // 未知单位返回NaN,避免程序崩溃 .alias("value_tb") ])?; // 可选:移除中间临时列 df = df.drop(["split_value", "num", "unit"])?; println!("{}", df); Ok(()) }
内容的提问来源于stack exchange,提问作者NotABot83
相关产品推荐
相关产品推荐

