2015-01-12 2 views
5

У меня проблемы с пониманием модели ref в ржавчине. Я имею в виду https://rustbyexample.com/scope/borrow/ref.htmlРжавчина пример: Образец ref

Вот код, который я не понимаю:

let point = Point { x: 0, y: 0 }; 

let _copy_of_x = { 
    // `ref_to_x` is a reference to the `x` field of `point` 
    let Point { x: ref ref_to_x, y: _ } = point; 

    // Return a copy of the `x` field of `point` 
    *ref_to_x 
}; 

Я понимаю, что последнее let выражение своего рода сопоставления с образцом (?). Поэтому я понимаю, что ref ref_to_x должен быть равен 0, значение x оригинала point.

Но я не понимаю, что на самом деле делает ref. Когда я добавить некоторый код, как это:

println!("x: {}", point.x); 
println!("ref_to_x: {}", ref_to_x); 
println!("*ref_to_x: {}", *ref_to_x); 

Я всегда получаю 0, так не кажется, что будет разница. Как-то я ожидаю адрес памяти для ref_to_x, а *ref_to_x может быть разыменованным значением.

Я могу заменить оба ref ref_to_x и *ref_to_xmyx и код все еще работает. Какая разница? Что делает ref?

изменить: после прочтения dbaupps ответьте и сделайте некоторое добавление с ref_to_x и *ref_to_x вещи стали немного яснее; вы не можете добавить целое число в ref_to_x, потому что это ссылка. Наверное, я запутался, потому что нет указания на ссылку, когда вы ее печатаете.

ответ

10

ref создает указатель в куске памяти, подкрепляются на, в этом случае, ref_to_x указывает непосредственно в память, которая хранит point.x, это то же самое, как написание let ref_to_x = &point.x в этом случае.

Образец чрезвычайно важен, поскольку он позволяет проникать глубоко внутри сложных структур данных, не нарушая иерархию владения. Например, если один имеет val: &Option<String>, написание

match *val { 
    Some(s) => println!("the string is {}", s), 
    None => println!("no string" 
} 

не является законным, он дает ошибку вроде:

<anon>:3:11: 3:15 error: cannot move out of borrowed content 
<anon>:3  match *val { 
        ^~~~ 
<anon>:4:14: 4:15 note: attempting to move value to here 
<anon>:4   Some(s) => {} 
        ^
<anon>:4:14: 4:15 help: to prevent the move, use `ref s` or `ref mut s` to capture value by reference 
<anon>:4   Some(s) => {} 
        ^

Это не законно, чтобы взять на себя ответственность (перемещение) из заимствованных значения, потому что что могло бы повредить вещь, из которой была заимствована стоимость (нарушая ее инварианты, заставляя данные неожиданно исчезать и т. д.).

Таким образом, вместо этого можно использовать ссылку только на точку в памяти с помощью заимствования &.


Там есть небольшая тонкость, потому что (а) point не заимствован, так что все в порядке, чтобы выйти из point (который потребляет владение point тоже означает, что она не может быть использована позже, если не перезапускается) , и (b) тип int равен Copy, поэтому он не переносит право собственности при использовании по значению. Вот почему использование myx вместо этого работает нормально. Если тип x был, скажем, String (который не Copy) и point был заимствован, то понадобится ref.

11

Ссылка, созданная с помощью ref, является точно такой же, как ссылка с &.

Разница заключается в том, где они разрешены в синтаксисе. ref в левой части задания - это как добавить & с правой стороны.

Эти выражения эквивалентны:

let ref x1 = y; 
let x2 = &y; 

Эта избыточность существует потому, что в сопоставлении с образцом & используется для требуют, чтобы ссылка уже существует, вместо того, чтобы сделать новый один:

let foo = 1; 
match foo { 
    ref x => { 
     /* x == &1 */ 
     match x { 
      &y => /* y == 1 */ 
     } 
    }, 
} 

(discussion)

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