Типажи Borrow
и AsRef
очень похожи, но в то же время
отличаются. Ниже приводится небольшая памятка об этих двух типажах.
Типаж Borrow
используется, когда вы пишете структуру данных и хотите
использовать владение и заимствование типа как синонимы.
Например, HashMap
имеет метод get
, который использует
Borrow
:
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> where K: Borrow<Q>, Q: Hash + Eq
Эта сигнатура является довольно сложной. Параметр K
— это то, что нас здесь
интересует. Он ссылается на параметр самого HashMap
:
struct HashMap<K, V, S = RandomState> {
Параметр 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));
Это возможно, так как стандартная библиотека содержит 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);
Это выведет a заимствовано: 5
дважды.
Типаж AsRef
является преобразующим типажом. Он используется в обобщённом коде
для преобразования некоторого значения в ссылку. Например:
let s = "Hello".to_string(); fn foo<T: AsRef<str>>(s: T) { let slice = s.as_ref(); }
Мы видим, что они вроде одинаковы: имеют дело с владением и заимствованием значения некоторого типа. Тем не менее, эти типажи немного отличаются.
Используйте Borrow
, когда вы хотите абстрагироваться от различных видов
заимствований, или когда вы строите структуру данных, которая использует
владеющие и заимствованные значения как эквивалентные. Например, это может
пригодиться в хэшировании и сравнении.
Используйте AsRef
, когда вы пишете обобщённый код и хотите непосредственно
преобразовать что-либо в ссылку.