编写通用交换函数

时间:2014-11-26 15:22:15

标签: rust

我试图学习Rust并希望编写一个简单的通用交换函数

fn swap<T>(i: &mut T, j: &mut T) {
    let tmp: T = *i;
    *i = *j;
    *j = tmp;
}
fn main() {
    let i: &int = &mut 5;
    let j: &int = &mut 6;
    println!("{} {}", i, j);
    swap(i, j);
    println!("{} {}", i, j);
}

但编译器会抛出错误消息:

helloworld.rs:2:18: 2:20 error: cannot move out of dereference of `&mut`-pointer
helloworld.rs:2     let tmp: T = *i;
                                 ^~
helloworld.rs:2:9: 2:12 note: attempting to move value to here
helloworld.rs:2     let tmp: T = *i;
                        ^~~
helloworld.rs:2:9: 2:12 help: to prevent the move, use `ref tmp` or `ref mut tmp` to capture value by reference
helloworld.rs:2     let tmp: T = *i;
                        ^~~
helloworld.rs:3:10: 3:12 error: cannot move out of dereference of `&mut`-pointer
helloworld.rs:3     *i = *j;
                         ^~
helloworld.rs:13:10: 13:11 error: cannot borrow immutable dereference of `&`-pointer `*i` as mutable
helloworld.rs:13     swap(i, j);
                          ^
helloworld.rs:13:13: 13:14 error: cannot borrow immutable dereference of `&`-pointer `*j` as mutable
helloworld.rs:13     swap(i, j);
                             ^
error: aborting due to 4 previous errors

我对Rust很陌生,我真的不能以任何方式处理这些错误。希望有人可以解释出错的原因和原因。

2 个答案:

答案 0 :(得分:4)

指针解除引用的问题是它违反了Rust的移动语义。您的函数是借用ij的引用,即使您被允许修改借来的值 - 例如:

fn assign<T>(i: &mut T, j: T) {
   *i = j;
}

完全没问题 - 你不被允许&#34;移动&#34;其他地方借来的价值,甚至是临时变量。这是因为借用只持续函数的调用,并且通过将所有权转移给函数来实现,这是不允许的。

解决此问题的一种方法(不使用unsafe代码)是复制值而不是移动它。您可以限制T实施Clone特征,这可以让您复制值,保持原始借用值不变:

fn swap<T: Clone>(i: &mut T, j: &mut T) {
    let tmp = i.clone();
    *i = j.clone();
    *j = tmp;
}
fn main() {
    let i: &mut int = &mut 5;
    let j: &mut int = &mut 6;
    println!("{} {}", i, j);
    swap(i, j);
    println!("{} {}", i, j);
}

另请注意,我必须制作ij &mut int,因为在您的代码中,您不可避免地借用了对值的引用。

答案 1 :(得分:3)

这里有两个问题,第一个是你在做的时候失去可变性:

let i: &int = &mut 5;

应表达为:

let i: &mut int = &mut 5;
// or
let i = &mut 5i;

后者当然被推荐为更简洁。

然而,第二个问题只是swap本质上是unsafe,因为编译器今天有点过于原始:它担心通过移出i swap调用者最终会引用移出的项目(悬空引用)并且没有意识到由于函数的构建方式,你可以保证其他东西将在呼叫者重新掌控之前填补该漏洞。

因此提供了此功能std::mem::swap,因此您无需亲自执行此操作。您可以仔细阅读其实现细节。