2015-09-02 3 views
2

Рассмотрим следующий код (on playground):Почему я не могу спрятать коробку?

// calling this function move the ownership of nbr to is_even 
// at the end of the function is_even doesn't give the ownership back 
fn is_even(nbr: Box<i32>) -> bool { 
    *nbr % 2 == 0 
} 

fn main() { 
    let integer = Box::new(42); 
    if is_even(integer) { 
     print!("is even "); 
    } 
    println!("{}", integer); 
} 

Я получаю следующее сообщение об ошибке:

example.rs:10:17: 10:24 error: use of moved value: `integer` [E0382] 
example.rs:10 println!("{}", integer); 

example.rs:7:13: 7:20 note: `integer` moved here because it has type `Box<i32>`, which is non-copyable 
example.rs:7 if is_even(integer) { 

Я не понимаю, почему. Хорошо, когда я звоню is_even, я даю право собственности на эту функцию, но в конце is_even эта функция больше не нуждается в собственности. Это непреложная (только для чтения) передача права собственности, поэтому мы уверены, что она не удаляется, когда main сдерживается integer -> кажется безопасным использовать его обратно.

Все еще есть эта ошибка. Почему и что такое обходной путь?

+1

Этот и другие смешные вещи ржавчины - так что я теоретизирую - связанные с тем, как они подходят к вещам. Теперь, очевидно, is_even() может работать с семантикой, которую вы предлагаете. Тем не менее, другая реализация is_even(), которая передавала бы аргумент некоторым другим функциям, которые могут или не могут сохраняться или меняться, или обрабатывать их в других потоках, изменят семантику. Не уверен, что мое объяснение верное, но именно так я объясняю это неинтуитивное поведение для себя. – BitTickler

+1

@BitTickler: это в основном это, да. Если вы передадите аргумент как «Box », то вы * отдаете его *, а функция 'is_even' свободна в том, чтобы мутировать его, передавать его и делать то, что он хочет, уверенный, что функция' main' isn он не сможет использовать его после завершения функции. –

ответ

4

Если вы хотите сохранить права собственности на свою коробку, то вы должны иметь is_evenзанять, а не владеть ею. Вот рабочая версия кода:

// calling this function move the ownership of nbr to is_even 
// at the end of the function is_even doesn't give the ownership back 
fn is_even(nbr: &Box<i32>) -> bool { 
    **nbr % 2 == 0 
} 

fn main() { 
    let integer = Box::new(42); 
    if is_even(&integer) { 
     print!("is even "); 
    } 
    println!("{}", integer); 
} 

Обратите внимание, что is_even в настоящее время принимает ссылку (с &) к коробке, и мы должны передать ссылку (опять же, с &), когда мы называем функция. Наконец, теперь функция работает скорее по ссылке, чем по значению, поэтому нам нужно добавить еще *, чтобы снять ссылку, прежде чем мы сможем ее использовать.

Однако, это хорошее правильное правило, чтобы избежать использования неперемещаемых ссылок на значения, которые содержат их содержимое (например, String или Vec или Box). Функция может быть переписана в следующем виде:

fn is_even(nbr: &i32) -> bool { 
    *nbr % 2 == 0 
} 

Это работает с любой ссылку на целое, а не только те, которые находятся в Box эс.

+1

<от кого-то на irc> Нет такой вещи, как непреложная собственность, которую вы можете перенести в изменчивую привязку и скрипку с ней, что вы хотите. – Moebius

6

, когда я называю is_even, я даю право собственности на эту функцию

Ровно. Вы передали право собственности. У вас его нет, и функция будет делать то, что она хочет. В этом случае он освободит память, поэтому определенно не может использовать ее после вызова.

, что функция не нуждается в собственность больше

Именно поэтому она отбрасывается.

Это неизменная (только для чтения) передача права собственности

Это не существует. Вы полностью передаете право собственности, нет никаких оснований.

поэтому мы уверены, что он не будет удален

На самом деле, мы уверены он освобождается, и это очень хорошая вещь. Руст управляет этим для нас, поэтому вам никогда не придется спрашивать: «Кто должен освободить это?»

Итак, как вы это исправите? Это просто: передайте ссылку на внутреннее значение, а не на весь ящик. Это заимствует значение (изменено или нет, до вас) и право собственности не передается.

fn is_even(nbr: &i32) -> bool { ... } 
+3

Я сделал ржавую почту, и вы ее не редактировали! Вы в хорошей форме? : p – Moebius

+0

Фактически передача права собственности не * постоянно * неизменна. После того, как вы получили право собственности через переход, у вас есть свободное владение, чтобы прямо изменить его на изменчивое, если хотите, когда захотите, хотя у вас есть выбор, чтобы не ссылаться на эту привилегию. Игровая площадка: http://is.gd/B6rHuM – LinearZoetrope