Как идиоматически копировать фрагмент?

В Go копирование фрагментов выполняется стандартно и выглядит следующим образом:

# It will figure out the details to match slice sizes
dst = copy(dst[n:], src[:m])

В Rust я не смог найти аналогичный метод в качестве замены. Что-то, что я придумал, выглядит так:

fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize {
    let mut c = 0;
    for (&mut d, &s) in dst.iter_mut().zip(src.iter()) {
        d = s;
        c += 1;
    }
    c
}

К сожалению, я получаю эту ошибку компиляции, которую я не могу решить:

error[E0384]: re-assignment of immutable variable 'd'
 --> src/main.rs:4:9
  |
3 |     for (&mut d, &s) in dst.iter_mut().zip(src.iter()) {
  |               - first assignment to 'd'
4 |         d = s;
  |         ^^^^^ re-assignment of immutable variable

Как я могу установить d? Есть ли лучший способ скопировать фрагмент?

Ответы

Ответ 1

Да, используйте метод clone_from_slice(), он является общим для любого типа элемента, который реализует Clone.

fn main() {
    let mut x = vec![0; 8];
    let y = [1, 2, 3];
    x[..3].clone_from_slice(&y);
    println!("{:?}", x);
    // Output:
    // [1, 2, 3, 0, 0, 0, 0, 0]
}

Пункт назначения x является либо срезом &mut [T], либо чем-либо, что derefs к нему, как измененный Vec<T> вектор. Вам нужно нарезать место назначения и источник так, чтобы их длина соответствовала.


Начиная с Rust 1.9, вы также можете использовать copy_from_slice(). Это работает одинаково, но использует Copy признак вместо Clone и является прямой оболочкой memcpy. Компилятор может оптимизировать clone_from_slice, чтобы быть эквивалентным copy_from_slice, когда это применимо, но он может быть полезен.

Ответ 2

Предупреждение copy_memory устарело с Rust 1.6.0. Проверьте bluss ' для стабильного решения.


Я бы использовал copy_memory, который имеет почти ту же подпись, что и вы:

use std::slice::bytes;
use std::cmp;

fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize {
    let len = cmp::min(src.len(), dst.len());
    bytes::copy_memory(&mut dst[..len], &src[..len]);
    len
}

fn main() {
    let mut a = [1u8, 2, 3];
    let mut b = [9u8];

    //copy_slice(&mut a[], &b[]);
    copy_slice(&mut b[], &a[]);

    println!("{:?}, {:?}", a, b);
}

Обратите внимание, что это не общее решение. В ржавчине срезы могут быть любого типа, включая те, которые нелегко копировать! Ваш вопрос и этот ответ касаются только фрагментов u8.

Ответ 3

Этот код работает, хотя я не уверен, что это лучший способ сделать это.

fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize {
    let mut c = 0;
    for (d, s) in dst.iter_mut().zip(src.iter()) {
        *d = *s;
        c += 1;
    }
    c 
}

По-видимому, не указав разрешения доступа, явно сделал трюк. Тем не менее, я все еще смущен этим, и моя ментальная модель еще не охватывает то, что действительно происходит там. Мои решения в основном являются пробными и ошибочными, когда дело доходит до этих вещей, и я бы предпочел по-настоящему понять.

Ответ 4

Другим вариантом будет

fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize {
    dst.iter_mut().zip(src).map(|(x, y)| *x = *y).count()
}

Обратите внимание, что в этом случае вы должны использовать count, так как len будет использовать ярлык ExactSizeIterator и, таким образом, никогда не будет вызывать next, в результате получится no-op.