如何惯用地复制切片?

Posted

技术标签:

【中文标题】如何惯用地复制切片?【英文标题】:How to idiomatically copy a slice? 【发布时间】:2015-03-28 22:41:26 【问题描述】:

在 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] 切片,要么是任何与它无关的东西,例如可变的Vec<T> 向量。您需要对目标和源进行切片,以使它们的长度匹配。


从 Rust 1.9 开始,您还可以使用 copy_from_slice()。这工作方式相同,但使用 Copy 特征而不是 Clone,并且是 memcpy 的直接包装器。编译器可以将clone_from_slice 优化为等效于copy_from_slice(如果适用),但它仍然有用。

【讨论】:

谢谢!这是我最初寻找的内容,但在搜索与copy 相关的任何内容时找不到。用生锈的话来说,克隆可能是合适的术语……我仍然习惯了这一切。【参考方案2】:

另一种变体是

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

请注意,在这种情况下您必须使用count,因为len 将使用ExactSizeIterator 快​​捷方式,因此永远不会调用next,从而导致无操作。

【讨论】:

这不是惯用的 Rust。迭代器通常不应该有副作用,这里使用map 是双重非惯用的。如果这是您想要的,for 循环是正确的选择。 我承认这是一种 hack,但for 循环需要手动跟踪迭代次数。可以使用inspect 代替map,以更清楚地表明“结果”将被丢弃。 @Shepmaster 您可能需要考虑以下示例,该示例包含在collect() 的官方 Rust 文档中,它显示以下内容:let hello: String = chars.iter().map(|&x| x as u8).map(|x| (x + 1) as char).collect(); @code_dredd 谢谢,但这不是我的答案——我只是这里的编辑。 @Shepmaster 不用担心。我也不为这种实现或任何东西辩护。我只是想注意w.r.t的细节。迭代器和/或映射没有副作用。【参考方案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 

显然没有明确指定访问权限就可以了。然而,我仍然对此感到困惑,我的心智模型还没有涵盖那里真正发生的事情。 当涉及到这些事情时,我的解决方案大多是反复试验,我宁愿真正理解。

【讨论】:

你的方法是正确的。您的初始版本不起作用,因为取消引用模式(如&mut d)创建了一个新变量(在这种情况下为d)并将其分配给指针的取消引用。它不提供修改原始值的能力,它只是复制原始值;如果你使用非Copy 类型,你的程序甚至不会编译。 顺便说一句,你也可以保留&s,然后写*d = s

以上是关于如何惯用地复制切片?的主要内容,如果未能解决你的问题,请参考以下文章

将值从一个数据帧切片复制到另一个:使用“IndexSlice”的多索引熊猫数据帧的切片是不是总是一致地排序?

有效地将切片插入另一个切片

在 golang 中如何使用切片进行复制? [关闭]

如何通过析取语句(逻辑“或”)对 pandas DataFrame 进行切片? [复制]

如何在 Swift 中对字符串进行切片? [复制]

Python列表操作:遍历、range()、列表解析、列表切片、列表复制、元组