在闭包中解决自我借用领域的惯用解决方案是什么?

时间:2018-06-10 14:53:47

标签: struct rust closures borrow-checker borrowing

我编写了以下代码而没有预期借用检查器:

impl<C: Consumer> Transmit<C> {
    pub fn next(&mut self) -> Option<u8> {
        use State::*;
        match self.state {
            InPkt(pkt_left, 0) => {
               self.reader.read_bytes_maybe(1, |bytes| {
//             ^^^^
                    let len = bytes[0];
                    if len < pkt_left {
                        self.crc += len;
//                      ^^^^
                        self.state = InPkt(pkt_left - len, len);
                        (1, len)
                    } else {
                        self.state = AfterPkt;
                        (0, self.crc)
                    }
                }).or_else(|| {
                    self.state = AfterPkt;
                    Some(self.crc)
                })
            }
            InPkt(pkt_left, len_left) => {
                self.reader.read_byte().map(|b| {
                    self.state = InPkt(pkt_left, len_left - 1);
                    self.crc += b;
                    b
                })
            }
            AfterPkt => {
                self.crc = 0;
                self.state = InPkt(<u8>::max_value(), 0);
                Some(0)
            }
        }
    }
}


pub struct Transmit<R> {
    pub state: State,
    pub crc: u8, // simplified
    pub reader: R
}
#[derive(Clone, Copy)]
pub enum State {
    InPkt(u8, u8),
    AfterPkt,
}
pub trait Consumer {
    fn read_byte(&mut self) -> Option<u8>;
    // implemented on a buffer, with read_bytes_maybe you can peek at some bytes
    // (if there are enough) and then decide how many to actually consume
    fn read_bytes_maybe<R>(&mut self, u8, impl FnOnce(&[u8]) -> (u8, R)) -> Option<R>;
}

正如您可以在this playground中尝试一样,编译器会抱怨

  
error[E0500]: closure requires unique access to `self` but `self.reader` is already borrowed
  --> src/main.rs:7:48
   |
7  |                self.reader.read_bytes_maybe(1, |bytes| {
   |                ----------- borrow occurs here  ^^^^^^^ closure construction occurs here
...
11 |                         self.crc += len;
   |                         ---- borrow occurs due to use of `self` in closure
...
19 |                 }).or_else(|| {
   |                  - borrow ends here

我该如何解决这个问题?我的read_bytes_maybe设计是否有缺陷?我应该不使用闭包但有两个方法,一个用于创建具有内部状态的Read结构,第二个用于使用该结构?

我找到了两个&#34;解决方案&#34;,第一个避免在闭包中使用整个self但是单独借用字段:

InPkt(pkt_left, 0) => {
    let crc = &mut self.crc;
    let state = &mut self.state;
    self.reader.read_bytes_maybe(1, |bytes| {
        let len = bytes[0];
        if len < pkt_left {
            *crc += len;
            *state = InPkt(pkt_left - len, len);
            (1, len)
        } else {
            *state = AfterPkt;
            (0, *crc)
        }
    }).or_else(|| {
        *state = AfterPkt;
        Some(*crc)
    })
}

和第二个使用Option作为闭包返回值来对if的比较结果进行编码,然后仅更改state / crc

InPkt(pkt_left, 0) => {
    if let Some(len) = self.reader.read_bytes_maybe(1, |bytes| {
        let len = bytes[0];
        if len < pkt_left {
            (1, Some(len))
        } else {
            (0, None)
        }
    }).unwrap_or(None) {
        self.crc += len;
        self.state = InPkt(pkt_left - len, len);
        Some(len)
    } else {
        self.state = AfterPkt;
        Some(self.crc)
    }
}

我不喜欢他们中的任何一个,他们认为我是非惯用的,比原来更难理解。

0 个答案:

没有答案