1. 1. Introduction
  2. 2. Введение
  3. 3. C чего начать
  4. 4. Изучение Rust
    1. 4.1. Угадайка
    2. 4.2. Обедающие философы
    3. 4.3. Вызов кода на Rust из других языков
  5. 5. Синтаксис и семантика
    1. 5.1. Связывание имён
    2. 5.2. Функции
    3. 5.3. Простые типы
    4. 5.4. Комментарии
    5. 5.5. Конструкция `if`
    6. 5.6. Циклы
    7. 5.7. Владение
    8. 5.8. Ссылки и заимствование
    9. 5.9. Время жизни
    10. 5.10. Изменяемость
    11. 5.11. Структуры
    12. 5.12. Перечисления
    13. 5.13. Конструкция `match`
    14. 5.14. Шаблоны сопоставления `match`
    15. 5.15. Синтаксис методов
    16. 5.16. Вектора
    17. 5.17. Строки
    18. 5.18. Обобщённое программирование
    19. 5.19. Типажи
    20. 5.20. Типаж `Drop`
    21. 5.21. Конструкция `if let`
    22. 5.22. Типажи-объекты
    23. 5.23. Замыкания
    24. 5.24. Универсальный синтаксис вызова функций
    25. 5.25. Контейнеры и модули
    26. 5.26. `const` и `static`
    27. 5.27. Атрибуты
    28. 5.28. Псевдонимы типов
    29. 5.29. Приведение типов
    30. 5.30. Ассоциированные типы
    31. 5.31. Безразмерные типы
    32. 5.32. Перегрузка операций
    33. 5.33. Преобразования при разыменовании
    34. 5.34. Макросы
    35. 5.35. Сырые указатели
    36. 5.36. Небезопасный код
  6. 6. Эффективное использование Rust
    1. 6.1. Стек и куча
    2. 6.2. Тестирование
    3. 6.3. Условная компиляция
    4. 6.4. Документация
    5. 6.5. Итераторы
    6. 6.6. Многозадачность
    7. 6.7. Обработка ошибок
    8. 6.8. Выбор гарантий
    9. 6.9. Интерфейс внешних функций
    10. 6.10. Типажи `Borrow` и `AsRef`
    11. 6.11. Каналы сборок
    12. 6.12. Using Rust without the standard library
  7. 7. Нестабильные возможности Rust
    1. 7.1. Плагины к компилятору
    2. 7.2. Встроенный ассемблерный код
    3. 7.3. Без stdlib
    4. 7.4. Внутренние средства
    5. 7.5. Элементы языка
    6. 7.6. Продвинутое руководство по компоновке
    7. 7.7. Тесты производительности
    8. 7.8. Синтаксис упаковки и шаблоны `match`
    9. 7.9. Шаблоны `match` для срезов
    10. 7.10. Ассоциированные константы
    11. 7.11. Пользовательские менеджеры памяти
  8. 8. Глоссарий
  9. 9. Syntax Index
  10. 10. Библиография

Типажи `Borrow` и `AsRef`

Типажи Borrow и AsRef очень похожи, но в то же время отличаются. Ниже приводится небольшая памятка об этих двух типажах.

Типаж Borrow

Типаж Borrow используется, когда вы пишете структуру данных и хотите использовать владение и заимствование типа как синонимы.

Например, HashMap имеет метод get, который использует Borrow:

fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
    where K: Borrow<Q>,
          Q: Hash + EqRun

Эта сигнатура является довольно сложной. Параметр K — это то, что нас здесь интересует. Он ссылается на параметр самого HashMap:

struct HashMap<K, V, S = RandomState> {Run

Параметр K представляет собой тип ключа, который использует HashMap. Взглянем на сигнатуру get() еще раз. Использовать get() возможно, когда ключ реализует Borrow<Q>. Таким образом, мы можем сделать HashMap, который использует ключи String, но использовать &str, когда мы выполняем поиск:

use std::collections::HashMap;

let mut map = HashMap::new();
map.insert("Foo".to_string(), 42);

assert_eq!(map.get("Foo"), Some(&42));Run

Это возможно, так как стандартная библиотека содержит impl Borrow<str> for String.

Для большинства типов, когда вы хотите получить право собственности или позаимствовать значений, достаточно использовать просто &T. Borrow же становится полезен, когда есть более одного вида занимаемого значения. Это особенно верно для ссылок и срезов: у вас может быть как &T, так и &mut T. Если мы хотим принимать оба этих типа, Borrow как раз для этого подходит:

use std::borrow::Borrow;
use std::fmt::Display;

fn foo<T: Borrow<i32> + Display>(a: T) {
    println!("a заимствовано: {}", a);
}

let mut i = 5;

foo(&i);
foo(&mut i);Run

Это выведет a заимствовано: 5 дважды.

Типаж AsRef

Типаж AsRef является преобразующим типажом. Он используется в обобщённом коде для преобразования некоторого значения в ссылку. Например:

let s = "Hello".to_string();

fn foo<T: AsRef<str>>(s: T) {
    let slice = s.as_ref();
}Run

Что в каком случае следует использовать?

Мы видим, что они вроде одинаковы: имеют дело с владением и заимствованием значения некоторого типа. Тем не менее, эти типажи немного отличаются.

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

Используйте AsRef, когда вы пишете обобщённый код и хотите непосредственно преобразовать что-либо в ссылку.