使用 Option<&mut> 2 次
Use Option<&mut> 2 times
以下程序可以正常编译:
fn write_u16(bytes: &mut Vec<u8>, value: u16) {
bytes.push((value >> 8) as u8);
bytes.push(value as u8);
}
fn write_u32(bytes: &mut Vec<u8>, value: u32) {
write_u16(bytes, (value >> 16) as u16);
write_u16(bytes, value as u16);
}
现在我将字节类型更改为 Option<&mut Vec>:
fn write_u16(bytes_opt: Option<&mut Vec<u8>>, value: u16) {
if let Some(bytes) = bytes_opt {
bytes.push((value >> 8) as u8);
bytes.push(value as u8);
}
}
fn write_u32(bytes_opt: Option<&mut Vec<u8>>, value: u32) {
write_u16(bytes_opt, (value >> 16) as u16);
write_u16(bytes_opt, value as u16);
}
程序现在无法编译:
main.rs:10:15: 10:24 error: use of moved value: `bytes_opt`
main.rs:10 write_u16(bytes_opt, value as u16);
^~~~~~~~~
main.rs:9:15: 9:24 note: `bytes_opt` moved here because it has type `core::option::Option<&mut collections::vec::Vec<u8>>`, which is non-copyable
main.rs:9 write_u16(bytes_opt, (value >> 16) as u16);
^~~~~~~~~
error: aborting due to previous error
我不太明白,为什么我不能使用两次选项,我该如何解决这个问题?
我能想到的解决这个问题的唯一方法是:
fn write_u32(bytes_opt: Option<&mut Vec<u8>>, value: u32) {
if let Some(bytes) = bytes_opt {
write_u16(Some(bytes), (value >> 16) as u16);
write_u16(Some(bytes), value as u16);
} else {
write_u16(None, (value >> 16) as u16);
write_u16(None, value as u16);
}
}
但这不是很好的代码。
错误消息告诉你他们的关键事情:
bytes_opt
moved here because it has type core::option::Option<&mut collections::vec::Vec<u8>>
, which is non-copyable
您的函数签名声明它将消耗参数:
fn write_u16(bytes_opt: Option<&mut Vec<u8>>, value: u16)
// ^~~~~~~~~~~~~~~~~~~~
但是,通过使用它,它也会使用 可变引用。如果您有其他类型,例如 Option<u8>
或 Option<&Vec<u8>>
,那么编译器可以为您插入变量的隐式副本。但是,您不允许制作 可变引用 的副本,因为那样的话您将拥有 可变别名 ,编译器出于内存安全的考虑不允许这样做原因。
当您只传递 &mut Vec<u8>
时,编译器能够跟踪引用并看到一次只有一个项目具有引用,因此它允许它。但是,当可变引用嵌入到另一种类型中时,它无法跟踪。
为了让它真正起作用,它有点难看,mut
限定符比我想要的多:
fn write_u16(bytes_opt: &mut Option<&mut Vec<u8>>, value: u16) {
if let Some(ref mut bytes) = *bytes_opt {
bytes.push((value >> 8) as u8);
bytes.push(value as u8);
}
}
fn write_u32(mut bytes_opt: Option<&mut Vec<u8>>, value: u32) {
write_u16(&mut bytes_opt, (value >> 16) as u16);
write_u16(&mut bytes_opt, value as u16);
}
在@ChrisMorgan 的提示下,我找到了适合您原版的东西 API:
fn write_u16(bytes_opt: Option<&mut Vec<u8>>, value: u16) {
if let Some(bytes) = bytes_opt {
bytes.push((value >> 8) as u8);
bytes.push(value as u8);
}
}
fn write_u32(bytes_opt: Option<&mut Vec<u8>>, value: u32) {
if let Some(bytes) = bytes_opt {
write_u16(Some(bytes), (value >> 16) as u16);
write_u16(Some(bytes), value as u16);
}
}
虽然我怀疑在这种情况下你不应该这样做(正如已经评论过的那样),但在这种情况下可以安全地重新借用可变引用:
fn write_u32(mut bytes_opt: Option<&mut Vec<u8>>, value: u32) {
write_u16(bytes_opt.as_mut().map(|x| &mut **x), (value >> 16) as u16);
write_u16(bytes_opt, value as u16);
}
bytes_opt.as_mut().map(|x| &mut **x)
也可以写成match bytes_opt { Some(&mut ref mut x) => Some(x), None => None, }
。一个非常令人费解的模式(从左到右阅读它:&mut
——取消引用包含的值,ref mut
——然后对其进行新的可变引用),但它有效并避免了所有权问题.
以下程序可以正常编译:
fn write_u16(bytes: &mut Vec<u8>, value: u16) {
bytes.push((value >> 8) as u8);
bytes.push(value as u8);
}
fn write_u32(bytes: &mut Vec<u8>, value: u32) {
write_u16(bytes, (value >> 16) as u16);
write_u16(bytes, value as u16);
}
现在我将字节类型更改为 Option<&mut Vec>:
fn write_u16(bytes_opt: Option<&mut Vec<u8>>, value: u16) {
if let Some(bytes) = bytes_opt {
bytes.push((value >> 8) as u8);
bytes.push(value as u8);
}
}
fn write_u32(bytes_opt: Option<&mut Vec<u8>>, value: u32) {
write_u16(bytes_opt, (value >> 16) as u16);
write_u16(bytes_opt, value as u16);
}
程序现在无法编译:
main.rs:10:15: 10:24 error: use of moved value: `bytes_opt`
main.rs:10 write_u16(bytes_opt, value as u16);
^~~~~~~~~
main.rs:9:15: 9:24 note: `bytes_opt` moved here because it has type `core::option::Option<&mut collections::vec::Vec<u8>>`, which is non-copyable
main.rs:9 write_u16(bytes_opt, (value >> 16) as u16);
^~~~~~~~~
error: aborting due to previous error
我不太明白,为什么我不能使用两次选项,我该如何解决这个问题?
我能想到的解决这个问题的唯一方法是:
fn write_u32(bytes_opt: Option<&mut Vec<u8>>, value: u32) {
if let Some(bytes) = bytes_opt {
write_u16(Some(bytes), (value >> 16) as u16);
write_u16(Some(bytes), value as u16);
} else {
write_u16(None, (value >> 16) as u16);
write_u16(None, value as u16);
}
}
但这不是很好的代码。
错误消息告诉你他们的关键事情:
bytes_opt
moved here because it has typecore::option::Option<&mut collections::vec::Vec<u8>>
, which is non-copyable
您的函数签名声明它将消耗参数:
fn write_u16(bytes_opt: Option<&mut Vec<u8>>, value: u16)
// ^~~~~~~~~~~~~~~~~~~~
但是,通过使用它,它也会使用 可变引用。如果您有其他类型,例如 Option<u8>
或 Option<&Vec<u8>>
,那么编译器可以为您插入变量的隐式副本。但是,您不允许制作 可变引用 的副本,因为那样的话您将拥有 可变别名 ,编译器出于内存安全的考虑不允许这样做原因。
当您只传递 &mut Vec<u8>
时,编译器能够跟踪引用并看到一次只有一个项目具有引用,因此它允许它。但是,当可变引用嵌入到另一种类型中时,它无法跟踪。
为了让它真正起作用,它有点难看,mut
限定符比我想要的多:
fn write_u16(bytes_opt: &mut Option<&mut Vec<u8>>, value: u16) {
if let Some(ref mut bytes) = *bytes_opt {
bytes.push((value >> 8) as u8);
bytes.push(value as u8);
}
}
fn write_u32(mut bytes_opt: Option<&mut Vec<u8>>, value: u32) {
write_u16(&mut bytes_opt, (value >> 16) as u16);
write_u16(&mut bytes_opt, value as u16);
}
在@ChrisMorgan 的提示下,我找到了适合您原版的东西 API:
fn write_u16(bytes_opt: Option<&mut Vec<u8>>, value: u16) {
if let Some(bytes) = bytes_opt {
bytes.push((value >> 8) as u8);
bytes.push(value as u8);
}
}
fn write_u32(bytes_opt: Option<&mut Vec<u8>>, value: u32) {
if let Some(bytes) = bytes_opt {
write_u16(Some(bytes), (value >> 16) as u16);
write_u16(Some(bytes), value as u16);
}
}
虽然我怀疑在这种情况下你不应该这样做(正如已经评论过的那样),但在这种情况下可以安全地重新借用可变引用:
fn write_u32(mut bytes_opt: Option<&mut Vec<u8>>, value: u32) {
write_u16(bytes_opt.as_mut().map(|x| &mut **x), (value >> 16) as u16);
write_u16(bytes_opt, value as u16);
}
bytes_opt.as_mut().map(|x| &mut **x)
也可以写成match bytes_opt { Some(&mut ref mut x) => Some(x), None => None, }
。一个非常令人费解的模式(从左到右阅读它:&mut
——取消引用包含的值,ref mut
——然后对其进行新的可变引用),但它有效并避免了所有权问题.