尝试将一个 Vec 的内容复制到另一个 Vec 中,如何使用 copy_from_slice()?

Joc*_*lyn 5 memory vector rust

我正在尝试将a 的内容复制Vec到现有的 中Vec,替换 target 的内容Vec

这是我正在寻找的:

  • 不需要分配新内存(除非目标Vec太短),因为目标Vec已经分配
  • 它不应该使用迭代器,因为内存复制应该足以完成这项工作
  • Vec不应更改来源
  • 理想情况下应该使用安全的方法

这是我尝试过的:

  • vec.clone():给出正确的内容,但分配新的内存,这对于复制到已经存在的足够大的内存中来说是不需要的Vec
  • vec.clear(); vec.extend();:就地复制,但似乎在每个元素上使用迭代器,这不需要,我只想要一个 memcopy
  • vec.copy_from_slice():是我正在寻找的,但需要完全相同大小的缓冲区,由于某种原因我似乎无法得到

什么不起作用

#![feature(shrink_to)]
fn vec_copy(src: &Vec<i32>, dst: &mut Vec<i32>) {
    // Try to adjust dst buffer size... there should be a better way
    if src.len() > dst.len() {
        let addon = src.len() - dst.len();
        dst.reserve_exact(addon);
    } else {
        dst.shrink_to(src.len());
    }
    // Do the copy        
    // panics! :
    // thread 'main' panicked at libcore/slice/mod.rs:1645:9
    // 'destination and source slices have different lengths'
    // 
    dst.copy_from_slice(src.as_slice()); // <--- panics here
}

fn main() {
    // Copy from a shorter Vec
    let mut container = vec![1, 2];
    let test1 = vec![3]; // shorter vec
    println!("{:p} = {:?}", &container[0], container); // output: 0x7f00bda20008 = [1, 2]
    vec_copy(&test1, &mut container); // panics inside function 
    println!("{:p} = {:?}", &container[0], container); // expected: 0x7f00bda20008 = [3]

    // Copy from a longer Vec
    container = vec![1, 2];    
    let test2 = vec![4, 5, 6]; // longer Vec
    println!("{:p} = {:?}", &container[0], container); // output: 0x7fef5b820018 = [1, 2]
    vec_copy(&test2, &mut container); // panics inside function
    println!("{:p} = {:?}", &container[0], container); // expected: 0x7fef5b820018 = [4, 5, 6]    
}
Run Code Online (Sandbox Code Playgroud)

出现错误时出现恐慌:

#![feature(shrink_to)]
fn vec_copy(src: &Vec<i32>, dst: &mut Vec<i32>) {
    // Try to adjust dst buffer size... there should be a better way
    if src.len() > dst.len() {
        let addon = src.len() - dst.len();
        dst.reserve_exact(addon);
    } else {
        dst.shrink_to(src.len());
    }
    // Do the copy        
    // panics! :
    // thread 'main' panicked at libcore/slice/mod.rs:1645:9
    // 'destination and source slices have different lengths'
    // 
    dst.copy_from_slice(src.as_slice()); // <--- panics here
}

fn main() {
    // Copy from a shorter Vec
    let mut container = vec![1, 2];
    let test1 = vec![3]; // shorter vec
    println!("{:p} = {:?}", &container[0], container); // output: 0x7f00bda20008 = [1, 2]
    vec_copy(&test1, &mut container); // panics inside function 
    println!("{:p} = {:?}", &container[0], container); // expected: 0x7f00bda20008 = [3]

    // Copy from a longer Vec
    container = vec![1, 2];    
    let test2 = vec![4, 5, 6]; // longer Vec
    println!("{:p} = {:?}", &container[0], container); // output: 0x7fef5b820018 = [1, 2]
    vec_copy(&test2, &mut container); // panics inside function
    println!("{:p} = {:?}", &container[0], container); // expected: 0x7fef5b820018 = [4, 5, 6]    
}
Run Code Online (Sandbox Code Playgroud)

问题

usingvec.copy_from_slice()似乎是将 a 的内容内存复制到Vec另一个中的方法,无需不必要的内存分配,也无需使用迭代器。

如何设置目标的大小Vec以免vec.copy_from_slice()出现恐慌?

She*_*ter 4

你要Vec::extend_from_slice

fn vec_copy(src: &[i32], dst: &mut Vec<i32>) {
    // Optionally truncate to zero if there might be existing data
    // dst.clear();
    dst.extend_from_slice(src);
}
Run Code Online (Sandbox Code Playgroud)

这避免了在添加比先前分配的元素更多的元素时需要用“虚拟值”填充向量。

如果您在发布模式下查看程序集,它会memcpy在确定有足够的分配空间后调用:

playground::vec_copy:
    pushq   %r15
    pushq   %r14
    pushq   %r12
    pushq   %rbx
    subq    $88, %rsp
    movq    %rdx, %rbx
    movq    %rsi, %r15
    movq    %rdi, %r14
    movq    8(%rbx), %rsi
    movq    16(%rbx), %r12
    movq    %rsi, %rax
    subq    %r12, %rax
    cmpq    %r15, %rax
    jae .LBB1_14
    addq    %r15, %r12
    jb  .LBB1_8
    leaq    (%rsi,%rsi), %rax
    cmpq    %rax, %r12
    cmovbq  %rax, %r12
    movl    $4, %ecx
    movq    %r12, %rax
    mulq    %rcx
    jo  .LBB1_8
    testq   %rsi, %rsi
    je  .LBB1_9
    shlq    $2, %rsi
    movq    (%rbx), %rdi
    movq    %rsp, %r9
    movl    $4, %edx
    movl    $4, %r8d
    movq    %rax, %rcx
    callq   __rust_realloc@PLT
    testq   %rax, %rax
    jne .LBB1_5
    movq    (%rsp), %rax
    jmp .LBB1_12

.LBB1_9:
    movq    %rsp, %rdx
    movl    $4, %esi
    movq    %rax, %rdi
    callq   __rust_alloc@PLT
    testq   %rax, %rax
    je  .LBB1_12

.LBB1_5:
    xorl    %ecx, %ecx
    movdqa  32(%rsp), %xmm0
    movdqa  %xmm0, 48(%rsp)
    testq   %rcx, %rcx
    je  .LBB1_13

.LBB1_6:
    movq    %rax, (%rsp)
    movaps  48(%rsp), %xmm0
    movups  %xmm0, 8(%rsp)
    leaq    64(%rsp), %rdi
    movq    %rsp, %rsi
    callq   <core::heap::CollectionAllocErr as core::convert::From<core::heap::AllocErr>>::from@PLT
    movdqa  64(%rsp), %xmm0
    movq    %xmm0, %rax
    cmpq    $3, %rax
    je  .LBB1_14
    cmpq    $2, %rax
    jne .LBB1_15

.LBB1_8:
    leaq    .Lbyte_str.5(%rip), %rdi
    callq   core::panicking::panic@PLT
    ud2

.LBB1_12:
    movups  8(%rsp), %xmm0
    movaps  %xmm0, 32(%rsp)
    movl    $1, %ecx
    movdqa  32(%rsp), %xmm0
    movdqa  %xmm0, 48(%rsp)
    testq   %rcx, %rcx
    jne .LBB1_6

.LBB1_13:
    movq    %rax, (%rbx)
    movq    %r12, 8(%rbx)

.LBB1_14:
    movq    16(%rbx), %rdi
    leaq    (%rdi,%r15), %rax
    movq    %rax, 16(%rbx)
    shlq    $2, %r15
    shlq    $2, %rdi
    addq    (%rbx), %rdi
    movq    %r14, %rsi
    movq    %r15, %rdx
    callq   memcpy@PLT
    addq    $88, %rsp
    popq    %rbx
    popq    %r12
    popq    %r14
    popq    %r15
    retq

.LBB1_15:
    movq    80(%rsp), %rax
    movdqa  %xmm0, (%rsp)
    movq    %rax, 16(%rsp)
    movq    %rsp, %rdi
    callq   <alloc::heap::Heap as core::heap::Alloc>::oom
    ud2
Run Code Online (Sandbox Code Playgroud)
println!("{:p} = {:?}", &container[0], container);
Run Code Online (Sandbox Code Playgroud)

container.as_ptr()比向量为空时更明显&container[0]并且不会失败。

也可以看看: