简体   繁体   English

使用Option <&mut> 2次

[英]Use Option<&mut> 2 times

The following program compiles fine: 以下程序可以正常编译:

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);
}

now I'll change bytes type to Option<&mut Vec>: 现在,我将字节类型更改为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);
}

The program doesn't compile now: 该程序现在无法编译:

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

I don't really understand, why I can't use Option twice and how do I solve this problem? 我不太了解,为什么不能两次使用Option,如何解决此问题?

The only way I can imagine to solve this problem is: 我可以想象解决该问题的唯一方法是:

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);
    }
}

but that's not very nice code. 但这不是很好的代码。

Although I suspect in this case you should not be doing this (as commented already), it is possible to reborrow mutable references for this sort of a case where it is safe: 尽管我怀疑在这种情况下您不应该这样做(正如已经评论过的那样),但是在这种情况下,可以在安全的情况下重新借用可变引用:

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);
}

The bytes_opt.as_mut().map(|x| &mut **x) could also be written match bytes_opt { Some(&mut ref mut x) => Some(x), None => None, } . bytes_opt.as_mut().map(|x| &mut **x)也可以match bytes_opt { Some(&mut ref mut x) => Some(x), None => None, }写入。 A pretty mind-bending pattern (read it from left to right: &mut —dereference the contained value, ref mut —and then take a new mutable reference to it), but it works and avoids the ownership issue. 一个漂亮的弯弯曲曲的模式(从左到右读取: &mut mut-取消引用所包含的值, ref mut mut-然后对其进行新的可变引用),但是它有效并且避免了所有权问题。

The error message is telling you they key things: 错误消息告诉您他们的关键事项:

bytes_opt moved here because it has type core::option::Option<&mut collections::vec::Vec<u8>> , which is non-copyable bytes_opt移至此处,因为其类型为core::option::Option<&mut collections::vec::Vec<u8>> ,该类型不可复制

Your function signature states that it is going to consume the argument: 您的函数签名指出它将使用该参数:

fn write_u16(bytes_opt: Option<&mut Vec<u8>>, value: u16)
//                      ^~~~~~~~~~~~~~~~~~~~

However, by consuming it, it also consumes the mutable reference. 然而,消费它,它也消耗了可变引用。 If you had another type like Option<u8> or Option<&Vec<u8>> , then the compiler could just insert an implicit copy of the variable for you. 如果您具有Option<u8>Option<&Vec<u8>>类的其他类型,则编译器可以为您插入变量的隐式副本。 However, you aren't allowed to make copies of mutable references , because then you would have mutable aliases , which the compiler disallows for memory-safety reasons. 但是,您不允许制作可变引用的副本,因为那样的话您将拥有可变别名 ,出于内存安全的原因,编译器不允许使用这些别名

When you pass just the &mut Vec<u8> , the compiler is able to track the reference and see that only one item has the reference at a time, so it allows it. 当仅传递&mut Vec<u8> ,编译器便能够跟踪引用,并且一次只能看到一个条目具有引用,因此它允许它。 However, it is unable to track that when the mutable reference is embedded in another type. 但是,当可变引用嵌入另一种类型时,它无法跟踪。

To actually get it to work, it's a bit ugly, with more mut qualifiers than I would like: 要使其真正发挥作用,它有点难看,并且有更多的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);
}

Prompted by @ChrisMorgan, I got something that fits your original API: 在@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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM