Примитивный тип 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: ?Sized | fn eq(&self, other: &&B) -> bool |
impl<A, B> PartialEq<&B> for &mut A where A: PartialEq<B> + ?Sized, B: ?Sized | fn eq(&self, other: &&B) -> bool |
impl<A, B> PartialEq<&mut B> for &A where A: PartialEq<B> + ?Sized, B: ?Sized | fn eq(&self, other: &&mut B) -> bool |
impl<A, B> PartialEq<&mut B> for &mut A where A: PartialEq<B> + ?Sized, B: ?Sized | fn eq(&self, other: &&mut B) -> bool |
Реализации PartialOrd
| Тип | Реализация |
|---|---|
impl<A, B> PartialOrd<&B> for &A where A: PartialOrd<B> + ?Sized, B: ?Sized | fn partial_cmp(&self, other: &&B) -> Option<Ordering> |
impl<A, B> PartialOrd<&mut B> for &mut A where A: PartialOrd<B> + ?Sized, B: ?Sized | fn 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.0 | fn eq(&self, other: &&B) -> bool | Проверяет равенство значений self и other |
| 1.0.0 | fn ne(&self, other: &&B) -> bool | Проверяет неравенство значений self и other |
| 1.0.0 | fn partial_cmp(&self, other: &&B) -> Option<Ordering> | Возвращает упорядочивание между self и other, если оно существует |
| 1.0.0 | fn lt(&self, other: &&B) -> bool | Проверяет, меньше ли self, чем other |
| 1.0.0 | fn le(&self, other: &&B) -> bool | Проверяет, меньше или равен ли self, чем other |
| 1.0.0 | fn gt(&self, other: &&B) -> bool | Проверяет, больше ли self, чем other |
| 1.0.0 | fn ge(&self, other: &&B) -> bool | Проверяет, больше или равен ли self, чем other |