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

开发Polars Rust Napi函数时遭遇借用检查器错误求协助

解决Polars Rust Napi from_rows函数的借用检查器错误

错误原因

报错returns a value referencing data owned by the current function的核心问题是:coerce_js_anyvalue返回的AnyValue持有了当前函数栈上临时数据的引用——闭包内创建的obj、从obj获取的unknown都是局部变量,闭包执行完毕后这些变量会被销毁,但AnyValue中的引用仍指向它们,导致悬空引用,Rust借用检查器直接拦截了这种不安全行为。

解决方案

要解决这个问题,必须确保AnyValue存储的是拥有所有权的数据,而非引用。具体步骤如下:

1. 调整AnyValue定义

检查你的AnyValue枚举,确保所有数据变体都是拥有所有权的类型:

// 错误示例(带引用)
enum AnyValue<'a> {
    Str(&'a str),
    // ...其他带引用的变体
}

// 正确示例(拥有所有权)
enum AnyValue {
    Str(String),
    Int(i64),
    Float(f64),
    Bool(bool),
    Null,
    // ...其他拥有所有权的变体
}

2. 修改coerce_js_anyvalue函数

将JS值转换为拥有所有权的Rust类型,避免返回引用,同时移除不必要的unsafe块:

// 示例:安全转换JS值到拥有所有权的AnyValue
fn coerce_js_anyvalue(unknown: &JsUnknown, dtype: &DataType) -> napi::Result<AnyValue> {
    match dtype {
        DataType::Utf8 => {
            let js_str = unknown.as_string()?;
            Ok(AnyValue::Str(js_str.into_utf8()?.into_owned()?))
        }
        DataType::Int64 => {
            let num = unknown.as_number()?.get_int64()?;
            Ok(AnyValue::Int(num))
        }
        DataType::Float64 => {
            let num = unknown.as_number()?.get_double()?;
            Ok(AnyValue::Float(num))
        }
        DataType::Boolean => {
            let val = unknown.as_bool()?;
            Ok(AnyValue::Bool(val))
        }
        _ => Ok(AnyValue::Null),
    }
}

3. 调整主函数逻辑

确保Row收集的是完全拥有所有权的AnyValue实例,修改后的核心代码如下:

#[napi(catch_unwind)]
pub fn from_rows(
    rows: Array,
    schema: Option<Wrap<Schema>>,
    infer_schema_length: Option<u32>,
    env: Env,
) -> napi::Result<JsDataFrame> {
    let schema = match schema {
        Some(s) => s.0,
        None => {
            let infer_schema_length = infer_schema_length.unwrap_or(100) as usize;
            let pairs = obj_to_pairs(&rows, infer_schema_length);
            infer_schema(pairs, infer_schema_length)
        }
    };
    let len = rows.len();
    let it: Vec<Row> = (0..len)
        .into_iter()
        .map(|idx| {
            let obj = rows
                .get::<Object>(idx as u32)
                .unwrap_or(None)
                .unwrap_or_else(|| env.create_object().unwrap());
            Row(schema
                .iter_fields()
                .map(|fld| {
                    let dtype = fld.dtype();
                    let key = fld.name();
                    match obj.get(key) {
                        Ok(Some(unknown)) => {
                            coerce_js_anyvalue(&unknown, dtype)
                                .unwrap_or(AnyValue::Null)
                        }
                        _ => AnyValue::Null,
                    }
                })
                .collect())
        })
        .collect();
    let df = DataFrame::from_rows_and_schema(&it, &schema).map_err(JsPolarsErr::from)?;
    Ok(df.into())
}

关键注意点

  • 绝对避免让AnyValue持有任何栈上数据的引用,所有数据都要转为堆分配的拥有所有权类型(比如String而非&str)。
  • 优先使用napi提供的安全API进行JS值与Rust值的转换,减少unsafe代码的使用,从根源上避免借用问题。

内容的提问来源于stack exchange,提问作者Franek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 08:37:37