Трейт AsMut
#![allow(unused)] fn main() { pub trait AsMut<T> where T: ?Sized, { // Обязательный метод fn as_mut(&mut self) -> &mut T; } }
Используется для дешёвого преобразования изменяемая-ссылка-в-изменяемую-ссылку.
Этот трейт похож на AsRef, но используется для преобразований между изменяемыми ссылками. Если вам нужно выполнить дорогое преобразование, лучше реализовать From с типом &mut T или написать пользовательскую функцию.
Примечание: Этот трейт не должен завершаться неудачей. Если преобразование может завершиться неудачей, используйте специальный метод, который возвращает Option<T> или Result<T, E>.
Обобщённые реализации
AsMut автоматически разыменовывается, если внутренний тип является изменяемой ссылкой (например: foo.as_mut() будет работать одинаково, если foo имеет тип &mut Foo или &mut &mut Foo).
Обратите внимание, что по историческим причинам вышесказанное в настоящее время не выполняется вообще для всех типов, которые можно изменяемо разыменовать, например, foo.as_mut() не будет работать так же, как Box::new(foo).as_mut(). Вместо этого многие умные указатели предоставляют реализацию as_mut, которая просто возвращает ссылку на указываемое значение (но не выполняет дешёвое преобразование ссылка-в-ссылку для этого значения). Однако AsMut::as_mut не следует использовать исключительно для изменяемого разыменования; вместо этого можно использовать "Deref coercion":
#![allow(unused)] fn main() { let mut x = Box::new(5i32); // Избегайте этого: // let y: &mut i32 = x.as_mut(); // Лучше просто написать: let y: &mut i32 = &mut x; }
Типы, которые реализуют DerefMut, должны рассматривать возможность добавления реализации AsMut<T> следующим образом:
#![allow(unused)] fn main() { impl<T> AsMut<T> for SomeType where <SomeType as Deref>::Target: AsMut<T>, { fn as_mut(&mut self) -> &mut T { self.deref_mut().as_mut() } } }
Рефлексивность
В идеале AsMut был бы рефлексивным, т.е. существовала бы реализация impl<T: ?Sized> AsMut<T> for T с as_mut, просто возвращающим свой аргумент без изменений. Такая обобщённая реализация в настоящее время не предоставляется из-за технических ограничений системы типов Rust (она перекрывалась бы с другой существующей обобщённой реализацией для &mut T where T: AsMut<U>, которая позволяет AsMut автоматически разыменовываться, см. "Обобщённые реализации" выше).
Тривиальная реализация AsMut<T> for T должна быть добавлена явно для конкретного типа T, где это необходимо или желательно. Обратите внимание, однако, что не все типы из std содержат такую реализацию, и они не могут быть добавлены внешним кодом из-за правил сиротства.
Примеры
Используя AsMut как трейт-границу для обобщённой функции, мы можем принимать все изменяемые ссылки, которые могут быть преобразованы в тип &mut T. В отличие от разыменования, которое имеет единственный целевой тип, для типа может быть несколько реализаций AsMut. В частности, Vec<T> реализует как AsMut<Vec<T>>, так и AsMut<[T]>.
В следующем примере функции caesar и null_terminate предоставляют обобщённый интерфейс, который работает с любым типом, который может быть преобразован дешёвым преобразованием изменяемая-ссылка-в-изменяемую-ссылку в байтовый срез ([u8]) или байтовый вектор (Vec<u8>) соответственно.
struct Document { info: String, content: Vec<u8>, } impl<T: ?Sized> AsMut<T> for Document where Vec<u8>: AsMut<T>, { fn as_mut(&mut self) -> &mut T { self.content.as_mut() } } fn caesar<T: AsMut<[u8]>>(data: &mut T, key: u8) { for byte in data.as_mut() { *byte = byte.wrapping_add(key); } } fn null_terminate<T: AsMut<Vec<u8>>>(data: &mut T) { // Использование необобщённой внутренней функции, которая содержит большую часть // функциональности, помогает минимизировать накладные расходы на мономорфизацию. fn doit(data: &mut Vec<u8>) { let len = data.len(); if len == 0 || data[len-1] != 0 { data.push(0); } } doit(data.as_mut()); } fn main() { let mut v: Vec<u8> = vec![1, 2, 3]; caesar(&mut v, 5); assert_eq!(v, [6, 7, 8]); null_terminate(&mut v); assert_eq!(v, [6, 7, 8, 0]); let mut doc = Document { info: String::from("Example"), content: vec![17, 19, 8], }; caesar(&mut doc, 1); assert_eq!(doc.content, [18, 20, 9]); null_terminate(&mut doc); assert_eq!(doc.content, [18, 20, 9, 0]); }
Обратите внимание, однако, что API не обязательно должны быть обобщёнными. Во многих случаях принятие &mut [u8] или &mut Vec<u8>, например, является лучшим выбором (тогда вызывающие стороны должны передавать правильный тип).
Обязательные методы
1.0.0 · Source
#![allow(unused)] fn main() { fn as_mut(&mut self) -> &mut T }
Преобразует этот тип в изменяемую ссылку на (обычно выводимый) входной тип.
Реализаторы
Сводная таблица реализаций трейта AsMut<T>
| Исходный тип | Целевой тип T | Описание преобразования |
|---|---|---|
&mut [T] | [T] | Изменяемая ссылка на срез → изменяемый срез |
&mut str | str | Изменяемая ссылка на строку → изменяемый строковый срез |
&mut String | str | Изменяемая ссылка на String → изменяемый строковый срез |
String | str | String → изменяемый строковый срез |
Vec<T> | [T] | Vec → изменяемый срез |
&mut Vec<T> | [T] | Изменяемая ссылка на Vec → изменяемый срез |
[T; N] | [T] | Массив → изменяемый срез |
&mut [T; N] | [T] | Изменяемая ссылка на массив → изменяемый срез |
Box<T> | T | Box → изменяемая ссылка на содержимое |
&mut Box<T> | T | Изменяемая ссылка на Box → изменяемая ссылка на содержимое |
Rc<T> | T | Rc → изменяемая ссылка на содержимое (только если нет других ссылок) |
&mut Rc<T> | T | Изменяемая ссылка на Rc → изменяемая ссылка на содержимое |
Arc<T> | T | Arc → изменяемая ссылка на содержимое (только если нет других ссылок) |
&mut Arc<T> | T | Изменяемая ссылка на Arc → изменяемая ссылка на содержимое |
Cell<T> | T | Cell → изменяемая ссылка на содержимое |
RefCell<T> | T | RefCell → изменяемая ссылка на содержимое |
Mutex<T> | T | Mutex → изменяемая ссылка на содержимое |
RwLock<T> | T | RwLock → изменяемая ссылка на содержимое |
Cow<'_, B> | B | Clone-on-write → изменяемая ссылка на содержимое |
VecDeque<T> | [T] | VecDeque → изменяемый срез |
&mut VecDeque<T> | [T] | Изменяемая ссылка на VecDeque → изменяемый срез |
PathBuf | str | PathBuf → изменяемый строковый срез |
&mut PathBuf | str | Изменяемая ссылка на PathBuf → изменяемый строковый срез |
OsString | str | OsString → изменяемый строковый срез (если валидный UTF-8) |
&mut OsString | str | Изменяемая ссылка на OsString → изменяемый строковый срез |