Примитивный тип reference (ссылка)

Ссылки, &T и &mut T.

Ссылка представляет заимствование некоторого владеемого значения. Вы можете получить её, используя операторы & или &mut на значении, или используя паттерны ref или ref mut.

Для тех, кто знаком с указателями, ссылка — это просто указатель, который предполагается выровненным, не нулевым и указывающим на память, содержащую допустимое значение типа T. Например, &bool может указывать только на аллокацию, содержащую целочисленные значения 1 (true) или 0 (false), но создание &bool, указывающего на аллокацию, содержащую значение 3, вызывает неопределённое поведение. Фактически, Option<&T> имеет то же представление в памяти, что и допускающий нулевое значение, но выровненный указатель, и может передаваться через границы FFI как таковой.

В большинстве случаев ссылки могут использоваться почти так же, как исходное значение. Доступ к полям, вызов методов и индексация работают одинаково (за исключением правил изменяемости, конечно). Кроме того, операторы сравнения прозрачно делегируют реализации ссылаемого значения, позволяя сравнивать ссылки так же, как владеемые значения.

Ссылки имеют прикреплённое к ним время жизни, которое представляет область действия, для которой заимствование действительно. Говорят, что время жизни "переживает" другое, если его представительная область действия равна или длиннее другой. Время жизни 'static является самым длинным временем жизни, представляющим общую продолжительность жизни программы. Например, строковые литералы имеют время жизни 'static, потому что текстовые данные встроены в двоичный файл программы, а не находятся в аллокации, которой нужно динамически управлять.

Ссылки &mut T могут быть свободно преобразованы в ссылки &T с тем же типом ссылаемого значения, а ссылки с более длинным временем жизни могут быть свободно преобразованы в ссылки с более коротким временем жизни.

PartialEq будет сравнивать значения, на которые ссылаются. Можно сравнить адрес ссылки, используя преобразование ссылка-указатель и равенство сырых указателей через ptr::eq.

#![allow(unused)]
fn main() {
use std::ptr;

let five = 5;
let other_five = 5;
let five_ref = &five;
let same_five_ref = &five;
let other_five_ref = &other_five;

assert!(five_ref == same_five_ref);
assert!(five_ref == other_five_ref);

assert!(ptr::eq(five_ref, same_five_ref));
assert!(!ptr::eq(five_ref, other_five_ref));
}

Для получения дополнительной информации об использовании ссылок см. раздел книги "Ссылки и заимствование".

Реализации трейтов

Трейты, реализованные для всех &T (независимо от типа ссылаемого значения):

ТрейтПримечание
Copy
CloneОбратите внимание, что это не будет делегировать реализации Clone типа T, если она существует!
Deref
Borrow
fmt::Pointer

Трейты для &mut T (независимо от типа ссылаемого значения):

Получает все вышеперечисленные трейты, кроме Copy и Clone (чтобы предотвратить создание нескольких одновременных изменяемых заимствований), плюс:

ТрейтОписание
DerefMut
BorrowMut

Трейты, реализованные для &T, если базовый T также реализует этот трейт:

ТрейтПримечание
Все трейты в std::fmt, кроме fmt::Pointer (который реализован независимо от типа ссылаемого значения) и fmt::Write
PartialOrd
Ord
PartialEq
Eq
AsRef
FnКроме того, &T получает FnMut и FnOnce, если T: Fn
Hash
ToSocketAddrs
Sync

Трейты для &mut T, если T реализует этот трейт:

Получает все вышеперечисленные трейты, кроме ToSocketAddrs, плюс:

ТрейтПримечание
AsMut
FnMutКроме того, &mut T получает FnOnce, если T: FnMut
fmt::Write
Iterator
DoubleEndedIterator
ExactSizeIterator
FusedIterator
TrustedLen
Send
io::Write
Read
Seek
BufRead

Кроме того, ссылки &T реализуют Send тогда и только тогда, когда T реализует Sync.

Примечание: Из-за приведения разыменования при вызове метода просто вызов метода трейта будет работать как со ссылками, так и с владеемыми значениями! Описанные здесь реализации предназначены для общих контекстов, где окончательный тип T является параметром типа или иным образом неизвестен локально.

Безопасность

Для всех типов T: ?Sized и для всех t: &T или t: &mut T, когда такие значения пересекают границу API, обычно должны соблюдаться следующие инварианты:

ИнвариантОписание
t не нулевой
t выровнен по align_of_val(t)
если size_of_val(t) > 0, то t разыменовываем для size_of_val(t) байтов

Если t указывает на адрес a, "разыменовываемость" для N байтов означает, что диапазон памяти [a, a + N) полностью содержится в одной аллокации.

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

Для обратного направления всё сложнее: когда небезопасный код передаёт аргументы в безопасные функции или возвращает значения из безопасных функций, они обычно должны как минимум не нарушать эти инварианты. Полные требования сильнее, поскольку ссылка обычно должна указывать на данные, которые безопасно использовать как тип T.

Ещё не решено, может ли небезопасный код временно нарушать эти инварианты на внутренних данных. Как следствие, небезопасный код, который временно нарушает эти инварианты на внутренних данных, может быть незвуковым или стать незвуковым в будущих версиях Rust в зависимости от того, как будет решён этот вопрос.

Таблицы реализаций трейтов

Реализации PartialEq

ТипРеализация
impl<A, B> PartialEq<&B> for &A where A: PartialEq<B> + ?Sized, B: ?Sizedfn eq(&self, other: &&B) -> bool
impl<A, B> PartialEq<&B> for &mut A where A: PartialEq<B> + ?Sized, B: ?Sizedfn eq(&self, other: &&B) -> bool
impl<A, B> PartialEq<&mut B> for &A where A: PartialEq<B> + ?Sized, B: ?Sizedfn eq(&self, other: &&mut B) -> bool
impl<A, B> PartialEq<&mut B> for &mut A where A: PartialEq<B> + ?Sized, B: ?Sizedfn eq(&self, other: &&mut B) -> bool

Реализации PartialOrd

ТипРеализация
impl<A, B> PartialOrd<&B> for &A where A: PartialOrd<B> + ?Sized, B: ?Sizedfn partial_cmp(&self, other: &&B) -> Option<Ordering>
impl<A, B> PartialOrd<&mut B> for &mut A where A: PartialOrd<B> + ?Sized, B: ?Sizedfn partial_cmp(&self, other: &&mut B) -> Option<Ordering>

Реализации CoerceUnsized

ТипРеализация
impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T where 'b: 'a, T: Unsize<U> + ?Sized, U: ?Sized
impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b mut T where 'b: 'a, T: Unsize<U> + ?Sized, U: ?Sized
impl<'a, T, U> CoerceUnsized<&'a mut U> for &'a mut T where T: Unsize<U> + ?Sized, U: ?Sized

Реализации DispatchFromDyn

ТипРеализация
impl<'a, T, U> DispatchFromDyn<&'a U> for &'a T where T: Unsize<U> + ?Sized, U: ?Sized
impl<'a, T, U> DispatchFromDyn<&'a mut U> for &'a mut T where T: Unsize<U> + ?Sized, U: ?Sized

Сводная таблица методов

ВерсияМетодОписание
1.0.0fn eq(&self, other: &&B) -> boolПроверяет равенство значений self и other
1.0.0fn ne(&self, other: &&B) -> boolПроверяет неравенство значений self и other
1.0.0fn partial_cmp(&self, other: &&B) -> Option<Ordering>Возвращает упорядочивание между self и other, если оно существует
1.0.0fn lt(&self, other: &&B) -> boolПроверяет, меньше ли self, чем other
1.0.0fn le(&self, other: &&B) -> boolПроверяет, меньше или равен ли self, чем other
1.0.0fn gt(&self, other: &&B) -> boolПроверяет, больше ли self, чем other
1.0.0fn ge(&self, other: &&B) -> boolПроверяет, больше или равен ли self, чем other