2014-11-26 4 views
2

Я пытаюсь научиться Ржавчина и хотите, чтобы написать простую обобщенную функцию подкачкиДать обобщенную функцию подкачки

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, и я действительно никак не могу с этим справиться. Надеюсь, кто-то может объяснить, что пойдет не так и почему.

+0

Сравните с «core :: mem :: swap». –

ответ

4

Проблема с разыменованием указателя заключается в нарушении семантики перемещения Rust's. Ваша функция заимствуют ссылки на i и j, и даже если вам разрешено изменять заимствованное значение - например:

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

абсолютно нормально - вы не могут «двигаться» заимствованное значение где-то иначе, даже во временную переменную. Это связано с тем, что заем длится до тех пор, пока вызывается функция, и перемещая значение, которое вы передаете право собственности на функцию, что недопустимо.

Один из способов обойти это (без использования кода 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); 
} 

замечает Также я должен был сделать i и j&mut int, так как в своем коде вы неизменно заимствовали ссылки на ценности.

+0

Это именно то решение, которое я нашел несколько минут назад, спасибо :) –

+1

Вам не нужно «Clone» в 'assign () ', BTW. Он никогда не называет 'clone()'. –

+0

Ах спасибо @ Владымир Матвеев, я не хотел иметь это там. –

3

Есть две проблемы, первое, что вы потери переменчивость при выполнении:

let i: &int = &mut 5; 

Оно должно быть выражено либо в виде:

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

рекомендованную Последнее существо, конечно, для того, чтобы быть более кратким.

Вторая проблема, однако, заключается в том, что просто swap неотъемлемо unsafe, потому что компилятор немного слишком примитивно сегодня: он боится, что, двигаясь из i в swap абонент положит конец вверх со ссылкой на moved- (оборвав ссылку) и не понимает, что из-за способа построения функции вы гарантируете, что что-то еще заполнит это отверстие до того, как вызывающий абонент вернется под контроль.

Эта функция, таким образом, предоставляется std::mem::swap, поэтому вам не нужно это делать самостоятельно. Вы можете подробно ознакомиться с его внедрением.

+0

Теперь я чувствую себя глупо, чем раньше, потому что проблема заключается в компиляторе, а не мне :) –

Смежные вопросы