Трейт AsRef
#![allow(unused)] fn main() { pub trait AsRef<T> where T: ?Sized, { // Обязательный метод fn as_ref(&self) -> &T; } }
Используется для эффективного преобразования ссылка-в-ссылку.
Этот трейт похож на AsMut, который используется для преобразований между изменяемыми ссылками. Если вам нужно выполнить дорогое преобразование, лучше реализовать From с типом &T или написать пользовательскую функцию.
Связь с Borrow
AsRef имеет ту же сигнатуру, что и Borrow, но Borrow отличается в нескольких аспектах:
- В отличие от
AsRef,Borrowимеет обобщённую реализацию для любогоTи может использоваться для принятия как ссылки, так и значения. (Смотрите также примечание о рефлексивностиAsRefниже.) Borrowтакже требует, чтобыHash,EqиOrdдля заимствованного значения были эквивалентны таковым для владеемого значения. По этой причине, если вы хотите заимствовать только одно поле структуры, вы можете реализоватьAsRef, но неBorrow.
Примечание: Этот трейт не должен завершаться неудачей. Если преобразование может завершиться неудачей, используйте специальный метод, который возвращает Option<T> или Result<T, E>.
Обобщённые реализации
AsRef автоматически разыменовывается, если внутренний тип является ссылкой или изменяемой ссылкой (например: foo.as_ref() будет работать одинаково, если foo имеет тип &mut Foo или &&mut Foo).
Обратите внимание, что по историческим причинам вышесказанное в настоящее время не выполняется вообще для всех типов, которые можно разыменовать, например, foo.as_ref() не будет работать так же, как Box::new(foo).as_ref(). Вместо этого многие умные указатели предоставляют реализацию as_ref, которая просто возвращает ссылку на указываемое значение (но не выполняет дешёвое преобразование ссылка-в-ссылку для этого значения). Однако AsRef::as_ref не следует использовать исключительно для разыменования; вместо этого можно использовать "Deref coercion":
#![allow(unused)] fn main() { let x = Box::new(5i32); // Избегайте этого: // let y: &i32 = x.as_ref(); // Лучше просто написать: let y: &i32 = &x; }
Типы, которые реализуют Deref, должны рассматривать возможность реализации AsRef<T> следующим образом:
#![allow(unused)] fn main() { impl<T> AsRef<T> for SomeType where T: ?Sized, <SomeType as Deref>::Target: AsRef<T>, { fn as_ref(&self) -> &T { self.deref().as_ref() } } }
Рефлексивность
В идеале AsRef был бы рефлексивным, т.е. существовала бы реализация impl<T: ?Sized> AsRef<T> for T с as_ref, просто возвращающим свой аргумент без изменений. Такая обобщённая реализация в настоящее время не предоставляется из-за технических ограничений системы типов Rust (она перекрывалась бы с другой существующей обобщённой реализацией для &T where T: AsRef<U>, которая позволяет AsRef автоматически разыменовываться, см. "Обобщённые реализации" выше).
Тривиальная реализация AsRef<T> for T должна быть добавлена явно для конкретного типа T, где это необходимо или желательно. Обратите внимание, однако, что не все типы из std содержат такую реализацию, и они не могут быть добавлены внешним кодом из-за правил сиротства.
Примеры
Используя трейт-границы, мы можем принимать аргументы разных типов, если они могут быть преобразованы в указанный тип T.
Например: Создав обобщённую функцию, которая принимает AsRef<str>, мы выражаем, что хотим принимать все ссылки, которые могут быть преобразованы в &str, как аргумент. Поскольку и String, и &str реализуют AsRef<str>, мы можем принимать оба как входные аргументы.
#![allow(unused)] fn main() { fn is_hello<T: AsRef<str>>(s: T) { assert_eq!("hello", s.as_ref()); } let s = "hello"; is_hello(s); let s = "hello".to_string(); is_hello(s); }
Обязательные методы
1.0.0 · Source
#![allow(unused)] fn main() { fn as_ref(&self) -> &T }
Преобразует этот тип в разделяемую ссылку на (обычно выводимый) входной тип.
Сводная таблица реализаций трейта AsRef<T>
| Исходный тип | Целевой тип T | Описание преобразования |
|---|---|---|
&[T] | [T] | Ссылка на срез → срез |
&mut [T] | [T] | Изменяемая ссылка на срез → срез |
&str | str | Ссылка на строку → строковый срез |
&mut str | str | Изменяемая ссылка на строку → строковый срез |
&String | str | Ссылка на String → строковый срез |
&OsStr | str | Ссылка на OsStr → строковый срез (если валидный UTF-8) |
&OsString | str | Ссылка на OsString → строковый срез (если валидный UTF-8) |
&Path | str | Ссылка на Path → строковый срез |
&PathBuf | str | Ссылка на PathBuf → строковый срез |
String | str | String → строковый срез |
OsString | str | OsString → строковый срез (если валидный UTF-8) |
PathBuf | str | PathBuf → строковый срез |
Cow<'_, B> | B | Clone-on-write → ссылка на содержимое |
Box<T> | T | Box → ссылка на содержимое |
Rc<T> | T | Rc → ссылка на содержимое |
Arc<T> | T | Arc → ссылка на содержимое |
Vec<T> | [T] | Vec → срез |
&Vec<T> | [T] | Ссылка на Vec → срез |
&mut Vec<T> | [T] | Изменяемая ссылка на Vec → срез |
[T; N] | [T] | Массив → срез |
&[T; N] | [T] | Ссылка на массив → срез |
&mut [T; N] | [T] | Изменяемая ссылка на массив → срез |
Cell<T> | T | Cell → неизменяемая ссылка на содержимое |
RefCell<T> | T | RefCell → неизменяемая ссылка на содержимое |
Mutex<T> | T | Mutex → неизменяемая ссылка на содержимое |
RwLock<T> | T | RwLock → неизменяемая ссылка на содержимое |