简体   繁体   English

如何将任意大小的矩阵传递给Rust中的函数?

[英]How to pass an arbitrary sized matrix to a function in Rust?

I have a 3x3 matrix (a 2D array) passed to a function: 我有一个传递给函数的3x3矩阵(2D数组):

let matrix: [[i32; 3]; 3] = [
    [0, 0, 0],
    [0, 1, 0],
    [0, 0, 0]
];

filter::convolve(&mut image, matrix, 1).unwrap();

The function is currently hardwired to accept 3x3 matrix: 该功能目前硬连线接受3x3矩阵:

pub fn convolve(src: &mut Image, matrix: [[i32; 3]; 3], divisor: i32) -> Result<&mut Image, String> {
    // ...
}

How would I pass a 3x3, 5x5, or any arbitrarily sized matrix to the same function? 如何将3x3,5x5或任意大小的矩阵传递给同一个函数?

Arrays have a fixed size, determined at compile time. 数组具有固定大小,在编译时确定。 Slices have a fixed size, determined at run-time . 切片具有固定的大小,在运行时确定。

The easiest thing to do is to accept a slice of slices: 最简单的方法是接受一片切片:

fn convolve(matrix: &[&[i32]]) {
    println!("{:?}", matrix);
}

fn main() {
    let matrix = &[
        &[0, 0, 0][..],
        &[0, 1, 0][..],
        &[0, 0, 0][..],
    ];
    convolve(matrix);
}

That's a bit annoying, as you have to use the slicing syntax ( &foo[..] ) to convert the literal arrays to slices. 这有点烦人,因为你必须使用切片语法&foo[..] )将文字数组转换为切片。 You could also accept a generic, which allows you to accept the above, but also anything that can be converted to a slice: 您也可以接受通用,它允许您接受上述内容,但也可以接受任何可以转换为切片的内容:

fn convolve<T, I>(matrix: &[T])
where
    T: AsRef<[I]>,
    I: std::fmt::Debug,
{
    for part in matrix {
        println!("{:?}", part.as_ref());
    }
}

fn main() {
    let matrix = &[
        [0, 0, 0],
        [0, 1, 0],
        [0, 0, 0],
    ];
    convolve(matrix);
}

As kosinix points out , there is no guarantee that &[&[i32]] will have rows of equal lengths; 正如kosinix指出的那样 ,并不能保证&[&[i32]]会有相同长度的行; it's possible to have a ragged array . 它可能有一个粗糙的阵列

The run-time solution to that is to iterate through all the rows and ensure all the lengths are the same. 对此的运行时解决方案是迭代所有行并确保所有长度都相同。 This can be reduced to checking just once if you create a newtype for matrices you have validated: 这可以减少到如果您对验证矩阵创建NEWTYPE检查只有一次:

struct Matrix<'a, T: 'a>(&'a [&'a [T]]);

impl<'a, T> Matrix<'a, T> {
    fn new(slice: &'a [&'a [T]]) -> Result<Self, ()> {
        if slice.is_empty() {
            return Ok(Matrix(slice));
        }

        let (head, tail) = slice.split_at(1);
        let expected = head[0].len();

        if tail.iter().map(|row| row.len()).all(|l| l == expected) {
            Ok(Matrix(slice))
        } else {
            Err(()) // return a real error here
        }
    }
}

Now, whenever you have a Matrix , you can be sure the rows are all the same length. 现在,只要有Matrix ,就可以确保行的长度都相同。

The compile-time solution... doesn't exist yet. 编译时解决方案......尚不存在。 These are called const generics . 这些被称为const泛型 The proposed syntax would be 建议的语法

fn convolve<const N: usize>(matrix: [[i32; N]; N]) 

There are stable workarounds available (such as generic-array ), but these may be limited in one fashion or another. 有可用的稳定解决方法(例如通用阵列 ),但这些可能以某种方式受到限制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM