Rust版Polars是否支持NewType数据类型?
在Rust的Polars中使用透明NewType包装的自定义类型
问题描述
我希望在Rust中使用polars crate,同时使用本质上是受支持原生类型的透明NewType包装器的自定义数据类型。以下是我尝试实现的简单示例,但无法运行(rustc-stable v1.79.0,polars v0.41.3):
use polars::prelude::*; #[repr(transparent)] struct NewType(f64); fn main() { let value1 = NewType(4.77); let value2 = NewType(-6.1); // 无法运行,因为Polars不识别`NewType` let ser = Series::new("a", &[value1, value2]); println!("{ser}"); }
编译器错误提示:
未为
polars::prelude::Series实现特征polars::prelude::NamedFrom<&[NewType; 2], _>。
由于Rust的孤儿规则,无法直接为Series实现NamedFrom特征。请问在polars-rust中使用NewType数据类型还有其他方法吗?
解决方案
1. 手动转换为原生类型后创建Series
这是最直接的方案:先将NewType实例转换为底层的原生类型,再传递给Polars构造Series:
use polars::prelude::*; #[repr(transparent)] struct NewType(f64); impl NewType { // 提供获取底层值的方法,也可以直接通过解构访问 fn inner(&self) -> f64 { self.0 } } fn main() { let value1 = NewType(4.77); let value2 = NewType(-6.1); // 转换为f64数组后创建Series let data: Vec<f64> = vec![value1.inner(), value2.inner()]; let ser = Series::new("a", &data); println!("{ser}"); }
2. 为NewType实现Polars的IntoSeries特征
通过为Vec<NewType>实现IntoSeries,可以让集合直接转换为Series,简化代码:
use polars::prelude::*; #[repr(transparent)] struct NewType(f64); // 实现Into<f64>方便转换为原生类型 impl Into<f64> for NewType { fn into(self) -> f64 { self.0 } } // 为Vec<NewType>实现IntoSeries特征 impl IntoSeries for Vec<NewType> { fn into_series(self) -> Series { // 转换为f64类型的ChunkedArray,再转为Series let ca: Float64Chunked = self.into_iter().map(Into::into).collect(); ca.into_series() } } fn main() { let value1 = NewType(4.77); let value2 = NewType(-6.1); // 直接将Vec<NewType>转换为Series并重命名 let ser = vec![value1, value2].into_series().rename("a"); println!("{ser}"); }
3. 实现Polars自定义类型(进阶)
如果需要在Polars操作全程保留NewType的类型语义,可以实现Polars的PolarsDataType等相关特征,将NewType注册为兼容的自定义类型:
use polars::prelude::*; use polars_core::datatypes::PolarsDataType; #[repr(transparent)] #[derive(Debug, Clone, Copy)] struct NewType(f64); // 实现PolarsDataType,复用f64的DataType impl PolarsDataType for NewType { fn get_dtype() -> DataType { DataType::Float64 } } // 实现与f64的互转 impl From<NewType> for f64 { fn from(val: NewType) -> Self { val.0 } } // 实现从NewType迭代器构造Float64Chunked impl FromIterator<NewType> for Float64Chunked { fn from_iter<I: IntoIterator<Item = NewType>>(iter: I) -> Self { iter.into_iter().map(Into::into).collect() } } fn main() { let value1 = NewType(4.77); let value2 = NewType(-6.1); let ca: Float64Chunked = vec![value1, value2].into_iter().collect(); let ser = ca.into_series().rename("a"); println!("{ser}"); }
内容的提问来源于stack exchange,提问作者QuantumDot
相关产品推荐
相关产品推荐

