在相同类型的两个可变位置交换值,而无需取消初始化或复制任何一个。
use std::mem; let x = &mut 5; let y = &mut 42; mem::swap(x, y); assert_eq!(42, *x); assert_eq!(5, *y);
(来自offical Rust doc)
如何在不复制的情况下交换两个值?值42
如何从y
变为x
?这不可能。
该函数实际上确实在内部进行复制:这是从文档中提取的源代码:
pub fn swap<T>(x: &mut T, y: &mut T) {
unsafe {
// Give ourselves some scratch space to work with
let mut t: T = uninitialized();
// Perform the swap, `&mut` pointers never alias
ptr::copy_nonoverlapping(&*x, &mut t, 1);
ptr::copy_nonoverlapping(&*y, x, 1);
ptr::copy_nonoverlapping(&t, y, 1);
// y and t now point to the same thing,
// but we need to completely forget `t`
// because it's no longer relevant.
forget(t);
}
}
previous answer的语义是正确的,但在详细信息上已过时。
逻辑上,交换两个值的方法是将值A读到临时位置,将B复制到A的顶部,然后将临时值写回到B。在很短的时间内,同一值在内存中存在两次。这就是为什么这些功能的[[implementation需要unsafe
代码的原因,因为只有人才能保证Rust的安全要求得到遵守。
mem::swap
is implemented as:mem::swap
[pub fn swap<T>(x: &mut T, y: &mut T) { // SAFETY: the raw pointers have been created from safe mutable references satisfying all the // constraints on `ptr::swap_nonoverlapping_one` unsafe { ptr::swap_nonoverlapping_one(x, y); } }
是私有的,但swap_nonoverlapping_one
是:
您可以查看pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) { // For types smaller than the block optimization below, // just swap directly to avoid pessimizing codegen. if mem::size_of::<T>() < 32 { let z = read(x); copy_nonoverlapping(y, x, 1); write(y, z); } else { swap_nonoverlapping(x, y, 1); } }
和ptr::copy_nonoverlapping
的文档。后者基本上是针对较大值进行复制的高度优化版本。