AsRef and AsMut
AsRef and AsMut: Borrowing Conversions
The AsRef and AsMut traits enable cheap reference-to-reference conversions. Unlike From and Into which transfer ownership, these traits allow you to borrow data as a different type without copying or moving it. This is incredibly useful for writing generic functions that can accept multiple types.
For example, a function that works with paths might want to accept &str, String, Path, or PathBuf. Instead of writing four different functions or forcing callers to convert their data, you can use AsRef<Path> to accept any of these types.
pub trait AsRef<T: ?Sized> {
fn as_ref(&self) -> &T;
}
pub trait AsMut<T: ?Sized> {
fn as_mut(&mut self) -> &mut T;
}The ?Sized bound allows these traits to work with dynamically-sized types like str and [T].
Standard Library Examples
// String implements AsRef<str>, AsRef<[u8]>,
// and AsRef<Path>
fn print_length<S: AsRef<str>>(s: S) {
println!("Length: {}", s.as_ref().len());
}
print_length("hello"); // &str
print_length(String::from("hi")); // String
// Vec<T> implements AsRef<[T]>
fn sum_slice<V: AsRef<[i32]>>(v: V) -> i32 {
v.as_ref().iter().sum()
}
sum_slice(&[1, 2, 3]); // &[i32]
sum_slice(vec![1, 2, 3]); // Vec<i32>Your Task
Implement the following functions and types using AsRef and AsMut:
1. Generic String Length Function
Implement string_length that accepts any type that can be borrowed as a string slice:
pub fn string_length<S: AsRef<str>>(s: S) -> usize2. Generic Slice Sum Function
Implement slice_sum that sums all elements in anything that can be borrowed as an i32 slice:
pub fn slice_sum<V: AsRef<[i32]>>(
values: V
) -> i323. Generic Contains Function
Implement contains_element that checks if a slice contains a specific element:
pub fn contains_element<V: AsRef<[i32]>>(
values: V,
target: i32
) -> bool4. Double All Elements (AsMut)
Implement double_all that doubles every element in a mutable slice:
pub fn double_all<V: AsMut<[i32]>>(values: &mut V)5. Custom Text Type with AsRef
Create a Text struct that wraps a String and implements:
AsRef<str>- borrow as a string sliceAsRef<[u8]>- borrow as a byte sliceAsMut<String>- mutable access to the inner string
pub struct Text {
content: String,
}
impl Text {
pub fn new(s: impl Into<String>) -> Self { ... }
}6. Generic Print Function
Implement print_as_uppercase that prints any string-like type in uppercase (return the uppercase string, don't actually print):
pub fn print_as_uppercase<S: AsRef<str>>(s: S) -> String7. Append to Buffer (AsMut)
Implement append_value that appends an i32 to anything that can be mutably borrowed as a Vec<i32>:
pub fn append_value<V: AsMut<Vec<i32>>>(
buffer: &mut V,
value: i32
)8. Path-like Operations
Implement get_extension that extracts a file extension from any path-like type:
pub fn get_extension<P: AsRef<std::path::Path>>(
path: P
) -> Option<String>Examples
use asref_asmut::*;
// String length works with &str and String
assert_eq!(string_length("hello"), 5);
assert_eq!(string_length(String::from("world")), 5);
// Slice sum works with arrays, slices, and vectors
assert_eq!(slice_sum(&[1, 2, 3]), 6);
assert_eq!(slice_sum(vec![10, 20]), 30);
// Contains element
assert!(contains_element(&[1, 2, 3], 2));
assert!(!contains_element(vec![1, 2, 3], 5));
// Double all elements
let mut arr = [1, 2, 3];
double_all(&mut arr);
assert_eq!(arr, [2, 4, 6]);
let mut vec = vec![5, 10];
double_all(&mut vec);
assert_eq!(vec, vec![10, 20]);
// Text type
let text = Text::new("Hello");
let s: &str = text.as_ref();
assert_eq!(s, "Hello");
let bytes: &[u8] = text.as_ref();
assert_eq!(bytes, b"Hello");
// Uppercase
assert_eq!(print_as_uppercase("hello"), "HELLO");
assert_eq!(
print_as_uppercase(String::from("World")),
"WORLD"
);
// Append value
let mut vec = vec![1, 2];
append_value(&mut vec, 3);
assert_eq!(vec, vec![1, 2, 3]);
// Path extension
assert_eq!(
get_extension("file.txt"),
Some("txt".to_string())
);
assert_eq!(
get_extension(
std::path::PathBuf::from("image.png")
),
Some("png".to_string())
);Hints
Click here to reveal hints
- Use
s.as_ref()to get a reference of the target type from a generic parameter - For
AsRef<str>, you can call string methods like.len(),.to_uppercase()on the result of.as_ref() - For
AsMut<[i32]>, use.as_mut()to get a mutable slice, then iterate with.iter_mut() - When implementing
AsReffor your own type, return a reference to the inner data Vec<T>implements bothAsRef<[T]>andAsMut<[T]>StringimplementsAsRef<str>,AsRef<[u8]>, andAsRef<Path>- For
get_extension, usePath::extension()which returnsOption<&OsStr>, then convert toString - The
?Sizedbound in the trait definition allows working with unsized types likestrand[T]
Run to execute your code and see test results here.