1

I have the following code:

pub type Blockchain<T> = Vec<Block<T>>;

pub fn blockchain() -> Blockchain<String> {
    let size = 10;
    let mut chain: Blockchain<String> = Vec::with_capacity(size);
    chain.push(Block::genesis());
    for i in 0..(size-1) {
        match chain.last_mut() {
            Some(tip) => chain.push(tip.next_block(String::from("yooooo"))),
            None      => {}
        }
    }
    chain
}

I'm getting an error:

error[E0499]: cannot borrow `chain` as mutable more than once at a time
  --> src/blockchain/mod.rs:33:26
   |
32 |         match chain.last_mut() {
   |               ----- first mutable borrow occurs here
33 |             Some(tip) => chain.push(tip.next_block(String::from("yooooo"))),
   |                          ^^^^^ second mutable borrow occurs here
34 |             None      => {}
35 |         }
   |         - first borrow ends here

How can I validly implement this in Rust?? So far I've tried using Box, Rc, and RefCell, with no luck.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
functorial
  • 687
  • 5
  • 13

1 Answers1

4

Right now, borrows in Rust are lexical. The error message shows that borrow of chain starts at chain.last_mut() and ends at the end of the match block. While it is possible to infer that borrow of chain ends before chain.push(...), Rust doesn't support it yet.

The general principle of solving such problems is to reorganize the code to end the borrow earlier. In your case it could be like this

let maybe_next_block = chain.last_mut().map(|tip| tip.next_block("some".into()));
// borrow of `chain` ended
match maybe_next_block {
    Some(block) => chain.push(block),
    None => {}
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
red75prime
  • 3,733
  • 1
  • 16
  • 22
  • Note that Rust will support this soon normally: https://github.com/rust-lang/rfcs/pull/2094 – Boiethios Aug 10 '17 at 07:19
  • 3
    @Boiethios "soon" is a *massive* simplification of the facts. The RFC hasn't even been accepted yet! **If** it's accepted, then all the arguments and details need to be sorted, it needs to be fully implemented, regression tested, then ride the release trains. In all, I'd be surprised if it lands in 2017. – Shepmaster Aug 10 '17 at 13:12
  • 2
    Use `if let` when you have a `match` where you only care about one arm. – Shepmaster Aug 10 '17 at 13:14
  • @Shepmaster Come on, don't break my dreams. About the **if** restriction, no doubt that this amelioration will be accepted soon or later, this is so a massive improvement that one cannot pass by it. – Boiethios Aug 10 '17 at 13:19
  • @Boiethios you are absolutely correct that it's important. However, it's been important since before Rust 1.0 was released (and I've seen **all** the duplicate Q&A that have arisen because of it since then). There's just a lot of work required to get from here to there; no amount of importance can make it disappear or go faster. Recall that MIR had to be completely designed and implemented as a step towards NLL. – Shepmaster Aug 10 '17 at 13:23
  • Ah, I was wondering what all those non-lexical posts were about on /r/rust. Thanks! – functorial Aug 10 '17 at 20:26