AsRef and AsMut
The AsRef<T> and AsMut<T> traits in std::convert perform cheap, infallible reference-to-reference conversions (&Self -> &T and &mut Self -> &mut T), enabling functions to accept multiple wrapper or borrowed types without copying or taking ownership.
Trait Definitions
pub trait AsRef<T: ?Sized> {
fn as_ref(&self) -> &T;
}
pub trait AsMut<T: ?Sized> {
fn as_mut(&mut self) -> &mut T;
}
Because T is bound by ?Sized, the target type T is frequently an unsized slice or trait object, such as str, [u8], Path, or OsStr.
Common Standard Library AsRef Implementations
| Source Type | Implements AsRef<T> For |
|---|---|
String and &str |
str, [u8], OsStr, Path |
Vec<T> and &[T] |
[T] |
PathBuf and &Path |
Path, OsStr |
Box<T>, Rc<T>, Arc<T> |
T |
Accepting Flexible Borrowed Inputs with impl AsRef<T>
Standard library filesystem functions (such as std::fs::read_to_string(path: impl AsRef<Path>)) use AsRef<Path> so callers can pass a &str, String, &Path, or PathBuf seamlessly. You can apply the same pattern with AsRef<str> or AsRef<[u8]>:
fn count_non_empty_lines(text: impl AsRef<str>) -> usize {
text.as_ref()
.lines()
.filter(|line| !line.trim().is_empty())
.count()
}
fn main() {
let literal: &str = "first\n\nsecond\n";
let owned: String = String::from("alpha\nbeta\ngamma");
println!("From &str: {}", count_non_empty_lines(literal));
println!("From String: {}", count_non_empty_lines(&owned));
println!("From owned: {}", count_non_empty_lines(owned));
}
From &str: 2
From String: 3
From owned: 3
Mutating Inner Buffers with AsMut<[T]>
Implementing or bounding by AsMut<[T]> allows generic in-place algorithms to operate on fixed-size arrays, slices, or Vec<T> alike:
fn zero_out(mut buffer: impl AsMut<[u8]>) {
for byte in buffer.as_mut() {
*byte = 0;
}
}
fn main() {
let mut arr = [1_u8, 2, 3, 4];
let mut vec = vec![9_u8, 8, 7];
zero_out(&mut arr);
zero_out(&mut vec);
println!("Array: {arr:?}");
println!("Vec: {vec:?}");
}
Array: [0, 0, 0, 0]
Vec: [0, 0, 0]