Понимание типа вывода - PullRequest
0 голосов
/ 24 апреля 2020

Мне кажется, у меня проблема как с типом данных, так и с владельцем iter. Сначала он объявляется внутри выражения for l oop. Я полагаю, что Rust делает вывод, что iter имеет тип u16, потому что он используется внутри моих вычислений в строке 4.

  1     let mut numbers: [Option<u16>; 5];                                          
  2     for iter in 0..5 {                                           
  3         let number_to_add: u16 = {  // `iter` moves to inner scope                                            
  4             ((iter * 5) + 2) / (4 * 16)  // Infers `iter: u16`                                 
  5         };                                                                   
  6                                                                                 
  7         numbers[iter] = Some(number_to_add);  // Expects `iter: usize`                 
  8     }      

Я получаю следующую ошибку:

error[E0277]: the type `[std::option::Option<u16>]` cannot be indexed by `u16`
  --> exercises/option/option1.rs:3:9
   |
7  |         numbers[iter] = Some(number_to_add);
   |         ^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
  • Я пытался привести iter к u16 внутри вычисления в строке 4, но все еще возникают проблемы.

Где мое заблуждение?

Ответы [ 3 ]

1 голос
/ 24 апреля 2020

Ваше предположение верно. И с вашим исправлением тоже все было в порядке (это привело к другой ошибке, см. Ниже).

Ваша первая проблема заключалась в том, что для индексации среза он должен иметь тип usize, поэтому либо

numbers[iter as usize] = Some(number_to_add);

или

((iter as u16 * 5) + 2) / (4 * 16)

приведет к правильному выводу типа через ржавчину c.

Ваша вторая проблема заключалась в том, что числа не были инициализированы, поэтому ржавчина c правильно предупреждает вас, когда Вы пытаетесь изменить номера. Присвоение значения, например,

let mut numbers: [Option<u16>; 5] = [None; 5];

, позволит вам скомпилировать вашу программу.

0 голосов
/ 24 апреля 2020

Ваши рассуждения верны. Просто добавьте, если вы хотите только инициализировать свой массив, вы можете также рассмотреть этот способ сделать это:

let arr_elem = |i: u16| Some(((i * 5) + 2) / (4 * 16));
let numbers : [Option<u16>; 5] = [
    arr_elem(0),
    arr_elem(1),
    arr_elem(2),
    arr_elem(3),
    arr_elem(4),
];

Таким образом, вам не нужно иметь его mut (за счет написание вспомогательной функции для инициализации отдельного элемента и определения элементов инициализатора, но это может быть автоматизировано, например, с помощью макроса или некоторых вспомогательных функций).

0 голосов
/ 24 апреля 2020

Помимо существующих ответов, подход более высокого уровня также может быть чище (в зависимости от вкуса)

let mut numbers = [None; 5];
for (i, n) in numbers.iter_mut().enumerate() {
    let iter = i as u16;
    let number_to_add: u16 = 
        ((iter * 5) + 2) / (4 * 16);

    *n = Some(number_to_add);
}

Другой альтернативой может быть более ленивый подход, но (afaik) нет способа например, try_collect в массив, только try_from срез в массив, так что вам нужно будет собрать () в ve c, затем try_from в массив, что кажется менее чем полезным. Хотя вы всегда можете использовать итератор для инициализации массива:

let mut it = (0u16..5).map(|i| ((i * 5) + 2) / (4 * 16));
let numbers = [it.next(), it.next(), it.next(), it.next(), it.next()];

Также

 // `iter` moves to inner scope

iter - это Copy, так что это просто ... скопировано. Своего рода. И блок также бесполезен, он содержит только простое выражение.

...