引用可能会让人很困惑,特别是对于不同类型的可变性。事实上,在我的调查中,只有三分之一的人说他们明白&mut &[T]是什么意思!
基本规则
在Rust中,要改变一个值,你需要对它有某种唯一的访问权,例如,一个&mut(对T的唯一可变引用)。另一方面,共享引用(&T)不能唯一访问。
因为共享引用没有唯一访问权,所以,如果你在一个类型中有一个共享引用,你不能通过它改变任何东西。
稍微简单一点的问题:&mut &T是什么意思?
如果一个共享引用不允许你改变它之后的任何东西,因此&mut &T不允许你改变类型T的值。虽然你不能改变T,但是你可以改变T的引用&T:
let value = 1;
let mut shared: &u32 = &value;
println!("{r:p}: {r} (value = {v})", r = shared, v = value);
// Prints <addr>: 1 (value = 1)
let unique: &mut &u32 = &mut shared;
*unique = &17;
println!("{r:p}: {r} (value = {v})", r = shared, v = value);
// Prints <different addr>: 17 (value = 1)
切片有什么不同?
使用&mut &[T],你仍然可以更改引用,使其指向另一个切片。但是&[T]本质上是一个胖指针,这意味着它不仅是一个指针,而且还包含切片的长度。
既然你可以改变引用,做为引用的一部分,存储长度也可以改变:
let mut slice: &[u8] = &[0, 1, 2, 3, 4];
let unique: &mut &[u8] = &mut slice;
// Since we want to hold unique reference,
// we can only access the slice through it
println!("({r:p}, {len}): {r:?}", r = *unique, len = unique.len());
// Prints (<addr>, 5): [0, 1, 2, 3, 4]
// Change only the length
*unique = &unique[..4];
println!("({r:p}, {len}): {r:?}", r = *unique, len = unique.len());
// Prints (<addr>, 4): [0, 1, 2, 3]
// Change both the pointer and the length
*unique = &unique[1..];
println!("({r:p}, {len}): {r:?}", r = *unique, len = unique.len());
// Prints (<addr+1>, 3): [1, 2, 3]
// Change only the pointer
*unique = &[17, 17, 42];
println!("({r:p}, {len}): {r:?}", r = *unique, len = unique.len());
// Prints (<different addr>, 3): [17, 17, 42]
一个真实的例子是io::Read为&[u8]实现了&mut &[T]:
use std::io::Read;
// We'll be reading *from* this slice
let mut data: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
// And *into* this
let mut buf = [0; 3];
while let Ok(1..) = Read::read(&mut data, &mut buf) {
println!("({r:p}, {len}): {r:?}", r = data, len = data.len());
// This will print:
// (<addr>, 7): [3, 4, 5, 6, 7, 8, 9]
// (<addr+3>, 4): [6, 7, 8, 9]
// (<addr+6>, 1): [9]
// (<addr+7>, 0): []
// In reality you'd also examine the `buf` contents here
}
现在你知道&mut &[T]的意思了吧!我希望这对你有帮助。
本文翻译自:
https://ihatereality.space/04-what-mutref-to-slice-ref-means/