在Rust中设置结构构造器的类型

时间:2018-11-30 22:51:30

标签: rust

我在Rust中有一个矩阵数据类型,它支持通用元素数据类型。

pub struct Matrix<T> {
    data: Vec<T>,  // row-major storage
    nrows: usize,
    ncols: usize,
}

我想创建一系列不同的矩阵构造函数,例如zeroeye,它们分别输出零矩阵和单位矩阵。标准的Matrix::new()构造函数很简单:

impl<T> Matrix<T> {
    pub fn new(data: Vec<T>, nrows: usize, ncols: usize) -> Matrix<T> {
        assert!(data.len() == nrows*ncols);

        Matrix { data: data, nrows: nrows, ncols: ncols }
    }
}

基础类型T是从初始化向量的类型推断出来的。但是,当我尝试编写Matrix::zero()构造函数时,由于要传递的唯一参数是大小,因此遇到了如何推断类型的问题。

impl<T> Matrix<T> {
    pub fn zero(nrows: usize, ncols: usize) -> Matrix<T>
    where T : Clone
    {
        let data: Vec<T> = vec![0; nrows*ncols];
        Matrix::new(data, nrows, ncols)
    }
}

尝试编译此错误消息:

error[E0308]: mismatched types                                                                                                                
  --> src/tools.rs:39:33                                                                                                                      
   |                                                                                                                                          
39 |         let data: Vec<T> = vec![0; nrows*ncols];                                                                                         
   |                                 ^ expected type parameter, found integral variable                                                       
   |                                                                                                                                          
   = note: expected type `T`                                                                                                                  
              found type `{integer}`     

我尝试了0 as TT::from(0),但这些问题仍无法解决。 (说实话,我还不明白为什么。)一种可能的解决方案是将函数定义更改为zero(_value: T, nrows: usize, ncols: usize)并通过vec![_value; ...]构造数据矢量,但这似乎很奇怪。

无论采用哪种解决方案,我的最终目标都是能够简单地编写

let a: Matrix<f32> = Matrix::zero(nrows, ncols);
// ... or ...
let b = Matrix<f32>::zero(nrows, ncols);
// ... or ...
let c = Matrix::zero<f32>(nrows, ncols);
// ... or something else?

1 个答案:

答案 0 :(得分:3)

您可能想使用num板条箱,该板条为这种情况添加了特征。

类似的东西:

extern crate num;
use num::Zero;

impl<T> Matrix<T> {
    pub fn zero(nrows: usize, ncols: usize) -> Matrix<T>
    where T : Clone + Zero
    {
        let data: Vec<T> = vec![T::zero(); nrows*ncols];
        Matrix::new(data, nrows, ncols)
    }
}

可能会起作用,因为它将您的矩阵类型定义为受实现num::Zero特征的类型所限制。这是在所有整数和浮点基元上实现的,也可以为自定义类型实现。

如果您不想导入num条板箱,则可以手动定义此特征,如下所示,尽管它需要您自己为基元实现。

trait Zero {
    fn zero() -> Self;
}
impl Zero for f32 {
    fn zero() -> Self {
        0.0
    }
}
...