% Типажи Borrow
и AsRef
Типажи Borrow
и AsRef
очень похожи, но в то же время
отличаются. Ниже приводится небольшая памятка об этих двух типажах.
Типаж Borrow
Типаж 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
Типаж AsRef
является преобразующим типажом. Он используется в обобщённом коде
для преобразования некоторого значения в ссылку. Например:
let s = "Hello".to_string();
fn foo<T: AsRef<str>>(s: T) {
let slice = s.as_ref();
}
Что в каком случае следует использовать?
Мы видим, что они вроде одинаковы: имеют дело с владением и заимствованием значения некоторого типа. Тем не менее, эти типажи немного отличаются.
Используйте Borrow
, когда вы хотите абстрагироваться от различных видов
заимствований, или когда вы строите структуру данных, которая использует
владеющие и заимствованные значения как эквивалентные. Например, это может
пригодиться в хэшировании и сравнении.
Используйте AsRef
, когда вы пишете обобщённый код и хотите непосредственно
преобразовать что-либо в ссылку.