2015-05-21 2 views
5

В rustc 1.0.0 я хотел бы написать функцию, которая мутирует двумерный массив, предоставленный вызывающим. Я надеялся, что это будет работать:Mutable многомерный массив как аргумент функции

fn foo(x: &mut [[u8]]) { 
    x[0][0] = 42; 
} 

fn main() { 
    let mut x: [[u8; 3]; 3] = [[0; 3]; 3]; 
    foo(&mut x); 
} 

Он не может скомпилировать:

$ rustc fail2d.rs 
fail2d.rs:7:9: 7:15 error: mismatched types: 
expected `&mut [[u8]]`, 
    found `&mut [[u8; 3]; 3]` 
(expected slice, 
    found array of 3 elements) [E0308] 
fail2d.rs:7  foo(&mut x); 
        ^~~~~~ 
error: aborting due to previous error 

Я считаю, что это говорит мне, что мне нужно как-то кормить функцию ломтик ломтиками, но я не знаю, как это построить.

Он «работает», если я жестко закодирую длину вложенного массива в сигнатуре функции. Это неприемлемо, поскольку я хочу, чтобы функция работала на многомерных массивах произвольного размера:

fn foo(x: &mut [[u8; 3]]) { // FIXME: don't want to hard code length of nested array 
    x[0][0] = 42; 
} 

fn main() { 
    let mut x: [[u8; 3]; 3] = [[0; 3]; 3]; 
    foo(&mut x); 
} 

tldr; любые способы нулевой стоимости передачи ссылки на многомерный массив, так что функции используют выражения типа $ x [1] [2] = 3; $?

+0

вас может заинтересовать https://github.com/rust-lang/rfcs/issues/1038 и соответствующий PR о параметрах общего значения –

ответ

6

Это сводится к вопросу о макете памяти. Предполагая тип T с размером, известным во время компиляции (это ограничение можно записать T: Sized), размер [T; n] известен во время компиляции (требуется n раз больше, чем T); но [T] - это нестандартный тип; его длина неизвестна во время компиляции. Поэтому его можно использовать только с помощью некоторой формы косвенности, например ссылки (&[T]) или коробки (Box<[T]>, хотя это имеет ограниченное практическое значение, с Vec<T>, что позволяет добавлять и удалять элементы, не перераспределяя их каждый раз с использованием общего назначения).

Кусочек нестандартного типа не имеет смысла; это разрешено по причинам, которые мне не понятны, но у вас никогда не может быть экземпляра. (Vec<T>, для сравнения, требует T: Sized.)

&[T; n] может принудить к &[T] и &mut [T; n] к &mut [T], но это применимо только на внешнем уровне; содержимое среза исправлено (вам нужно создать новый массив или вектор для достижения такого преобразования, потому что макет памяти каждого элемента отличается). Эффект от этого заключается в том, что массивы работают для одномерной работы, но для многомерной работы они разваливаются. Массивы в настоящее время очень востребованы гражданами второго сорта в Rust, и до тех пор, пока язык не поддержит создание кусочков общей длины, что, вероятно, в конечном итоге.

Я рекомендую использовать либо одномерную матрицу (подходящую для квадратных матриц, индексированную по x * width + y или аналогичным), либо векторы (Vec<Vec<T>>). Кроме того, могут быть библиотеки, которые уже абстрагируются над подходящим решением.

Смежные вопросы