Установка типа конструктора Struct в Rust - PullRequest
0 голосов
/ 01 декабря 2018

У меня есть матричный тип данных в Rust, который поддерживает тип данных универсального элемента.

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

Я хотел бы создать семейство различных конструкторов матриц, таких как zero и eye, которые выводятнулевая матрица и единичная матрица соответственно.Стандартный конструктор 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 T и T::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 голосов
/ 01 декабря 2018

Возможно, вы захотите использовать ящик 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
    }
}
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...