Почему размер ChunksExact <T> в Rust не известен во время компиляции

Я хотел бы скопировать один Vecв другой, в кусках из[u8; 4]присваивая только первые 3 элемента каждого фрагмента (оставив только 4-й). Это похоже на практический способ сделать это:

    let input_pix: Vec<u8> = ...;
    let mut output_pix: Vec<u8> = vec![255; input_pix.len()];
    for (input_chunk, output_chunk) in input_pix.chunks(4).zip(output_pix.chunks_exact_mut(4)) {
       let i: u8 = foo(...);
       output_chunk[0..2].clone_from_slice([i,3]);
    }

...НО компилятору это не нравится. Фактически нарезка output_chunkвообще выдает ошибку. Проще всего:

        ...
        for (input_chunk, output_chunk) in input_pix.chunks(4).zip(output_pix.chunks_exact_mut(4)) {
           let s = format!("{:?}", output_chunk[0..2]);
        }

Результаты в...

    |
40  |         let s = format!("{:?}", output_chunk[0..2]);
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time

Из документов:

Куски представляют собой кусочки и не перекрываются. Если chunk_size не делит длину среза, то последние элементы вплоть до chunk_size-1 будут опущены и могут быть извлечены из функции остатка итератора.

Поскольку каждый фрагмент имеет ровно элементы chunk_size, компилятор часто может оптимизировать полученный код лучше, чем в случае фрагментов.

Итак... кажется, это говорит о размере элементов ChunksExactMut (вернулся из chunks_exact_mut) точно, и в данном случае 4, что же дает? Зная размер при компиляции чувствует время, как это своего рода точку изChunksExactMut.

Я ошибаюсь? Есть ли еще какой-нибудь идиоматический способ скопировать фрагментChunksExactMut. Я могу просто копировать поэлементно с помощью цикла, но это кажется очень неприятным запахом. Или, возможно, что IS способ сделать это, и я должен позволить компилятору сделать работу?

1 ответ

Решение

TL;DR: просто измените его на

let s = format!("{:?}", &output_chunk[0..2]);
//                     ^^^ the important bit

При индексировании фрагмента (типа &[T]) по диапазону, возвращаемый тип [T]. Размер - это свойство типа, а не свойство значений. Так что даже если мы индексируем с известной шириной (т.е.0..2), мы по-прежнему получаем на выходе тип без размера.

Одним из недостатков отсутствия размера является то, что значения этого типа не могут быть переданы функциям. Таким образом, чтобы отформатировать элементы такого типа, как строка, мы должны передать указатель. Самый простой способ сделать это - просто одолжить кусок.

Не работает:

fn foo(slice: &[u8]) -> String {
    format!("{:?}", slice[0..2])
}

Работает:

fn foo(slice: &[u8]) -> String {
    format!("{:?}", &slice[0..2])
}
Другие вопросы по тегам