如何惯用地复制切片?
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”的多索引熊猫数据帧的切片是不是总是一致地排序?