Трейт 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]Изменяемая ссылка на срез → срез
&strstrСсылка на строку → строковый срез
&mut strstrИзменяемая ссылка на строку → строковый срез
&StringstrСсылка на String → строковый срез
&OsStrstrСсылка на OsStr → строковый срез (если валидный UTF-8)
&OsStringstrСсылка на OsString → строковый срез (если валидный UTF-8)
&PathstrСсылка на Path → строковый срез
&PathBufstrСсылка на PathBuf → строковый срез
StringstrString → строковый срез
OsStringstrOsString → строковый срез (если валидный UTF-8)
PathBufstrPathBuf → строковый срез
Cow<'_, B>BClone-on-write → ссылка на содержимое
Box<T>TBox → ссылка на содержимое
Rc<T>TRc → ссылка на содержимое
Arc<T>TArc → ссылка на содержимое
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>TCell → неизменяемая ссылка на содержимое
RefCell<T>TRefCell → неизменяемая ссылка на содержимое
Mutex<T>TMutex → неизменяемая ссылка на содержимое
RwLock<T>TRwLock → неизменяемая ссылка на содержимое