pub trait AsMut<T: ?Sized> {
// Required method
fn as_mut(&mut self) -> &mut T;
}
Expand description
用于进行廉价的可变到可变引用转换。
一个与 AsRef
类似的 trait,但用于在可变引用之间进行转换。如果需要进行昂贵的转换,最好用 &mut T
类型实现 From
或编写自定义函数。
注意:此 trait 一定不能失败。如果转换失败,请使用专用方法返回 Option<T>
或 Result<T, E>
。
泛型实现
AsMut
自动解引用,如果内部类型是不兼容引用 (例如: 如果 foo
具有 &mut Foo
或 &mut &mut Foo
类型,foo.as_mut()
将工作相同)。
请注意,由于历史原因,上述内容目前并不适用于所有 mutably dereferenceable types,例如 foo.as_mut()
不会与 Box::new(foo).as_mut()
一样工作。
相反,许多智能指针提供了一个 as_mut
实现,它简单地将一个引用返回给 pointed-to value (但不对该值执行廉价的引用 - 到 - 引用转换)。
但是,AsMut::as_mut
不应仅用于无效解引用; 可以使用 ‘Deref
coercion’ 代替:
let mut x = Box::new(5i32);
// 避免这种情况:
// let y: &mut i32 = x.as_mut();
// 最好只写:
let y: &mut i32 = &mut x;
Run实现 DerefMut
的类型应考虑添加 AsMut<T>
的实现,如下所示:
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()
}
}
RunReflexivity
理想情况下,AsMut
将是自反的,即有一个 impl<T: ?Sized> AsMut<T> for T
与 as_mut
简单地返回其参数不变。
由于 Rust 类型系统的技术限制,目前不提供这样的一揽子实现 (它将与 &mut T where T: AsMut<U>
的另一个现有一揽子实现重叠,它允许 AsMut
自动解引用,请参见上面的 “Generic Implementations”)。
必须在需要或需要的地方为特定类型 T
显式添加 AsMut<T> for T
的简单实现。但是请注意,并非 std
中的所有类型都包含这样的实现,并且由于孤儿规则,这些类型不能由外部代码添加。
Examples
使用 AsMut
作为 trait bound 作为泛型函数,我们可以接受所有可以转换为 &mut T
类型的引用。
与只有一个 target type 的 dereference 不同,一个类型可以有多个 AsMut
实现。特别是,Vec<T>
实现了 AsMut<Vec<T>>
和 AsMut<[T]>
。
在下文中,示例函数 caesar
和 null_terminate
提供了泛型接口,该接口适用于任何类型,可以通过廉价的转换为字节切片 ([u8]
) 或字节 vector (Vec<u8>
) 分别转换为字节切片 ([u8]
) 或字节 vector (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]);
}
Run但是请注意,API 不必是泛型。在许多情况下,例如使用 &mut [u8]
或 &mut Vec<u8>
是更好的选择 (调用者需要传递正确的类型)。