Типажи Borrow и AsRef
Типажи [Borrow]borrow и [AsRef]asref очень похожи, но в то же время
отличаются. Ниже приводится небольшая памятка об этих двух типажах.
Типаж Borrow
Типаж Borrow используется, когда вы пишете структуру данных и хотите
использовать владение и заимствование типа как синонимы.
Например, [HashMap]hashmap имеет метод [get]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, когда вы пишете обобщённый код и хотите непосредственно
преобразовать что-либо в ссылку.