Rust tip and trick — Borrow Link to heading
Rust Traits: Borrow vs AsRef
In this blog post, we will explore Rust trait Borrow. We will see how this differs from a similar cousin AsRef trait.
What are Borrow and AsRef? Link to heading
Borrow and AsRef are both traits that allow us to take reference as some other type. For example, suppose we have a String. We can use Borrow or AsRef to get a reference to a str.
let s = String::from("Hello");
let s_ref: &str = s.borrow(); // using Borrow
let s_ref: &str = s.as_ref(); // using AsRef
This is possible because String struct implements both Borrow<str> and AsRef<str>.


Looking at the function prototype, they look identical, returning &str type. In fact, they produce the same values too (Rust playground link)
use std::borrow::Borrow;
fn main() {
let s = String::from("Hello");
let s1: &str = s.borrow(); // using Borrow
let s2: &str = s.as_ref(); // using AsRef
assert_eq!(s1, s2);
}
So, the question is, how do they differ and when to use Borrow?
When to use Borrow? Link to heading
Borrow is a trait that is intended to be used for types that have a canonical way of borrowing as another type. A typical use case for Borrow is when you have a data that wraps around some internal type T for added functionalities. For example, String adds the functionality of mutability to str, so it is a superset of str, in terms of its features. In other words, String can do everything immutable that str can do. Similarly, Vec<T> is essentially a more flexible version of [T], so it again can do everything immutable that [T] can do, and so forth.
One requirement for implementing Borrow is that Hash, Eq and Ord for a borrowed value are equivalent to those of the owned value. This is the key difference from AsRef trait. If some data structure implements Borrow trait for T, then it must behave equivalently to T. Wit this requirement, the standard HashMap uses Borrow trait for get() and get_mut() methods.

Note that K is the key data type, which implements Borrow trait for Q. A typical type for K would be String, whereas a typical type for Q would be str. This means that we can pass any type Q that can be borrowed as a K. In our example, both String and &str implement Borrow<str>, so they can be used as keys. (Rust playground link)
use std::collections::HashMap;
fn main() {
let mut map = HashMap::new();
let key = String::from("key");
map.insert(key.clone(), 42);
// we can use a &String or a &str to get the value
assert_eq!(map.get("key"), Some(&42)); // &str
assert_eq!(map.get(&key), Some(&42)); // &String
}
There is a second key difference between Borrow and AsRef — Borrow has a blanket implementation for any type T. That is, you don’t need to trivially implement Borrow<T> for &T. This is more serious than it sounds like. Consider the following code (playground link)
struct MyStruct {
val: i64,
}
impl AsRef<i64> for MyStruct {
fn as_ref(&self) -> &i64 {
&self.val
}
}
fn print_i64(x: impl AsRef<i64>) {
println!("{}", x.as_ref());
}
fn main() {
let x = MyStruct { val: 314 };
print_i64(&1);
print_i64(x);
}
We want to be able to pass a direct reference of the number type i64 as well as any type that can behave like a reference to i64. Unfortunately, this code won’t compile, because, the trivial AsRef<i64> for &i64 is not implemented.
error[E0277]: the trait bound `{integer}: AsRef<i64>` is not satisfied
--> src/main.rs:17:16
|
17 | print_i64(&1);
| --------- ^ the trait `AsRef<i64>` is not implemented for `{integer}`
| |
| required by a bound introduced by this call
|
= note: required for `&{integer}` to implement `AsRef<i64>`
note: required by a bound in `print_i64`
--> src/main.rs:11:22
|
11 | fn print_i64(x: impl AsRef<i64>) {
| ^^^^^^^^^^ required by this bound in `print_i64`
On the other hand, Borrow works right out of the box.
use std::borrow::Borrow;
struct MyStruct {
val: i64,
}
impl Borrow<i64> for MyStruct {
fn borrow(&self) -> &i64 {
&self.val
}
}
fn print_i64(x: impl Borrow<i64>) {
println!("{}", x.borrow());
}
fn main() {
let x = MyStruct { val: 314 };
print_i64(&1);
print_i64(x);
}
Summary Link to heading
https://doc.rust-lang.org/std/convert/trait.AsRef.html#relation-to-borrow