2015-05-21 13 views
5

W rustc 1.0.0, chciałbym napisać funkcję, która mutuje dwuwymiarową tablicę dostarczoną przez wywołującego. Miałam nadzieję, że to będzie działać:Mutable wielowymiarowa tablica jako argument funkcji

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

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

To nie kompilacji:

$ 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 

wierzę, to mówi mi, że trzeba jakoś nakarmić funkcja plasterek plasterki, ale nie wiem jak to zbudować.

"Działa", jeśli ustawię długość zagnieżdżonej tablicy w sygnaturze funkcji. Jest to niedopuszczalne, ponieważ chcę, aby funkcja działała na wielowymiarowych tablicach o dowolnym wymiarze:

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; dowolne zero-kosztowe sposoby przekazywania odniesienia do tablicy wielowymiarowej, tak, że funkcja używa instrukcji takich jak $ x [1] [2] = 3; $?

+0

możesz być zainteresowany https://github.com/rust-lang/rfcs/issues/1038 i odpowiednim PR na temat ogólnych parametrów wartości –

Odpowiedz

6

Sprowadza się to do kwestii układu pamięci. Przyjmując typ T o rozmiarze znanym w czasie kompilacji (ograniczenie to można zapisać T: Sized), rozmiar [T; n] jest znany w czasie kompilacji (zajmuje to n razy tyle pamięci co T); ale [T] jest typem niezmienionym; jego długość nie jest znana podczas kompilacji. Z tego powodu można go używać tylko w niektórych formach pośrednictwa, takich jak odniesienie (&[T]) lub pole (Box<[T]>, choć ma to ograniczoną wartość praktyczną, z Vec<T>, co pozwala dodawać i usuwać elementy bez konieczności ponownego przydzielania za każdym razem za pomocą ogólnej alokacji).

Kawałek niezmienionego typu nie ma sensu; jest dozwolone z powodów, które nie są dla mnie jasne, ale nigdy nie możesz mieć jego instancji. (Vec<T>, dla porównania, wymaga T: Sized.)

&[T; n] może zmusić do &[T] i &mut [T; n] do &mut [T], ale dotyczy to tylko na poziomie najbardziej zewnętrznej; zawartość plasterka jest stała (aby utworzyć taką transformację, musisz utworzyć nową tablicę lub wektor, ponieważ układ pamięci każdego elementu jest inny). Efektem tego jest to, że macierze pracują nad pracą jednowymiarową, ale w przypadku pracy wielowymiarowej rozpadają się. Tablice są obecnie bardzo licznymi obywatelami drugiej kategorii w Rust i będą trwały do ​​momentu, gdy język będzie obsługiwał generowanie plasterków na całej długości, co w końcu może się skończyć.

Zaleca się stosowanie jednowymiarowych tablic (odpowiednich dla macierzy kwadratowych, indeksowanych przez x * width + y lub podobnych) lub wektorów (Vec<Vec<T>>). Mogą istnieć również biblioteki już omijające odpowiednie rozwiązanie.

Powiązane problemy