2015-10-15 3 views
3

Я пишу код в Rust (главным образом, как POC). Код принимает 2D-массив, передает его второй функции для выполнения математической математики (я знаю, что для этого есть стандартная библиотека, но я хочу привыкнуть к тому, как все работает).Назначение значений в 2D-массиве

Проблема в том, что назначение двумерного массива вызывает проблему.

Мой код выглядит следующим образом

fn main() 
{ 
    // first create a couple of arrays - these will be used 
    // for the vectors 
    let line1: [i32; 4] = [4, 2, 3, 3]; 
    let line2: [i32; 4] = [3, 4, 5, 7]; 
    let line3: [i32; 4] = [2, 9, 6, 2]; 
    let line4: [i32; 4] = [5, 7, 2, 4]; 

    // create two holding arrays and assign 
    let array_one = [line1, line3, line4, line2]; 
    let array_two = [line2, line1, line3, line4]; 

    // let's do the multiply 
    let result = matrix_multiply(&array_one, &array_two); 
    println!("{:?}", result); 
} 

fn matrix_multiply(vec1:&[&[i32;4];4], vec2:&[&[i32;4];4]) -> [[i32; 4];4] 
{ 
    // we need to deference the parameters passed in 
    let vec_one:[[i32;4];4] = vec1; 
    let vec_two:[[i32;4];4] = vec2; 

    // we need to store the sum 
    let mut sum = 0; 

    // we need to create the arrays to put the results into 
    let mut result = [[0i32; 4]; 4]; 

    // loop through the two vectors 
    for vone in 0..4 
    { 
     for vtwo in 0..4 
     { 
      for k in 0..4 
      { 
       sum = sum + vec1[[vone].k] * vec2[[k].vtwo]; 
      } 
      result[[vec_one].vec_two] = sum; 
      sum = 0; 
     } 
    } 

    return result; 
} 

Я также попытался result[vec_one][vec_two] = sum, но когда я пришел к компиляции, похоже, существует проблема присвоения массива.

Что я здесь делаю неправильно?

+0

Включите в вопрос сообщение об ошибке. – Shepmaster

ответ

3

Вот ваша ошибка, я считаю (по крайней мере один из них):

<anon>:15:34: 15:44 error: mismatched types: 
expected `&[&[i32; 4]; 4]`, 
    found `&[[i32; 4]; 4]` 
(expected &-ptr, 
    found array of 4 elements) [E0308] 
<anon>:15  let result = matrix_multiply(&array_one, &array_two); 
              ^~~~~~~~~~ 

Проблема заключается в том, ссылка или разыменования массивов не могут идти на нескольких уровнях их вложенности. Это связано с тем, что макет памяти, скажем, [&[i32; 4]; 4] и [[i32; 4]; 4] радикально отличается как по содержанию, так и по размеру. Первый массив состоит из четырех указателей на другие массивы (4 * 4 = 16/8 * 4 = 32 байта в целом, в зависимости от на архитектуре вашей машины), в то время как последний состоит из четырех массивов, выложенных последовательно (4 * 4 * 4 = всего 64 байта). Просто нет возможности перейти от [[i32; 4]; 4] к &[&[i32; 4]; 4] без перестройки внешнего массива, который Rust никогда не сделает для вас, потому что это слишком много волшебства.

Вам не нужно использовать внутреннюю ссылку; на самом деле вам, вероятно, даже не нужно передавать эти массивы по ссылке: массивы классов Copy также являются Copy, поэтому вы можете передавать их по значению. Они достаточно малы, чтобы не вызвать какие-либо влияния на производительность, и компилятор может оптимизировать его автоматически в любом случае:

fn main() { 
    // first create a couple of arrays - these will be used 
    // for the vectors 
    let line1: [i32; 4] = [4, 2, 3, 3]; 
    let line2: [i32; 4] = [3, 4, 5, 7]; 
    let line3: [i32; 4] = [2, 9, 6, 2]; 
    let line4: [i32; 4] = [5, 7, 2, 4]; 

    // create two holding arrays and assign 
    let array_one = [line1, line3, line4, line2]; 
    let array_two = [line2, line1, line3, line4]; 

    // let's do the multiply 
    let result = matrix_multiply(array_one, array_two); 
    println!("{:?}", result); 
} 

fn matrix_multiply(vec1: [[i32; 4]; 4], vec2: [[i32; 4]; 4]) -> [[i32; 4]; 4] { 
    // we need to create the arrays to put the results into 
    let mut result = [[0i32; 4]; 4]; 

    // loop through the two vectors 
    for vone in 0..4 { 
     for vtwo in 0..4 { 
      let mut sum = 0; 
      for k in 0..4 { 
       sum += vec1[vone][k] * vec2[k][vtwo]; 
      } 
      result[vone][vtwo] = sum; 
     } 
    } 

    result 
} 

(попробуйте это here)

Я также сделал ваш код более идиоматическим по току сообщества (расположение фигурных скобок, интервал и т. д.), и я исправил странный синтаксис для доступа к массивам.

+0

Спасибо за такой хорошо объясненный ответ. Мне нравится Rust :) – Nodoid

2

Если вы пишете

let line1: [i32; 4] = [4, 2, 3, 3]; 
let line2: [i32; 4] = [3, 4, 5, 7]; 
let line3: [i32; 4] = [2, 9, 6, 2]; 
let line4: [i32; 4] = [5, 7, 2, 4]; 

// create two holding arrays and assign 
let array_one = [line1, line3, line4, line2]; 

тип array_one будет [[i32;4];4], поскольку линейные массивы копируются в array_one. Заимствование этого через &array_one дает вам что-то типа &[[i32;4];4], которое очень отличается от &[&[T; 4]; 4] (что функция, которую вы пытаетесь назвать, ожидает).

Option1 - Создание [&[T; 4]; 4]:

let array_one = [&line1, &line3, &line4, &line2]; 
some_function(&array_one); 
... 
fn some_function(matrix: &[&[i32;4];4]) {...} 

Option2 - Изменение функции sitnature:

let array_one = [line1, line3, line4, line2]; 
some_function(&array_one); 
... 
fn some_function(matrix: &[[i32;4];4]) {...} 

Если вы заинтересованы в работе с многомерными массивами произвольных размеров, возможно, вы Я найду свой экспериментальный multiarray crate. Он в основном пытается предложить типы, подобные Box<[T]>, &[T] и &mut[T] для двух или более измерений.Вот непроверенный пример, чтобы получить представление о том, что я пытался сделать:

extern crate multiarray; 

use multiarray::*; 

fn main() { 
    // the backing memory will be a dynamically allocated 
    // linear array with 4 elements in row-major (C-style) order. 
    let mut matrix = Array2D::new([2, 2], 0i32); 
    matrix[[0,0]] = 1; matrix[[0,1]] = 2; 
    matrix[[1,0]] = 3; matrix[[1,1]] = 4; 
    let mut square = Array2D::new([2, 2], 0i32); 
    // the borrow methods create reference-like proxies 
    mat_product(matrix.borrow(), matrix.borrow(), 
       square.borrow_mut()); 
} 

fn mat_product(a: Array2DRef<i32>, b: Array2DRef<i32>, 
       mut c: Array2DRefMut<i32>) { 
    let rows = a.extents()[0]; // extent of 1st dimension 
    let intr = a.extents()[1]; // extent of 2nd dimension 
    let cols = b.extents()[1]; // extent of 2nd dimension 
    assert!(intr == b.extents()[0]); 
    assert!(rows == c.extents()[0]); 
    assert!(cols == c.extents()[1]); 
    for i in 0..rows { 
     // the i-th row of a and c... 
     let a_row_i = a.eliminated_dim(0, i); 
     let mut c_row_i = c.reborrow_mut().eliminated_dim(0, i); 
     for j in 0..cols { 
      c_row_i[j] = dot_product(a_row_i, b.eliminated_dim(1, j)); 
      //        ^^^j-th column of b^^^ 
     } 
    } 
} 

fn dot_product(a: Array1DRef<i32>, b: Array1DRef<i32>) -> i32 { 
    a.zip(b).fold(0, |acc,(&x,&y)| acc + x * y) 
} 
Смежные вопросы