Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cannot borrow foo as immutable because it is also borrowed as mutable

Tags:

rust

I have following (innocent enough) Rust code:

let file = &Path(some_file_name);
let mut buf = [0u8, ..12];
match io::file_reader(file) {
    Ok(reader) => reader.read(buf, buf.len()),
    Err(msg) => println(msg)
}

The rustc complains that

cannot borrow buf[] as immutable because it is also borrowed as mutable

If changing the corresponding line to:

Ok(reader) => reader.read(buf, 12),

all will work just fine. But it is less satisfactory since now the length of the buffer is duplicated in the code. Although vaguely understanding why rustc complains, I still would like to argue that rustc should be able to infer that len() is a pure function and has no side effect so the code is valid. Besides, it is a quite common patten to read into a buffer that way.

So what is the idiomatic Rust way here?

EDIT: The code was for Rust 0.8. As @pnkfelix pointed out, the Reader.read API has been changed since then. It doesn't need the second parameter any more.

like image 250
edwardw Avatar asked Dec 09 '13 19:12

edwardw


Video Answer


1 Answers

This answer is for my version of rustc: rustc 0.9-pre (61443dc 2013-12-01)

  1. The current version of the Reader trait has a different interface than the one you listed. Instead of taking both (a slice of) an output buffer and a length, it now just takes (a slice of) an output buffer. It can get the length of the output buffer from the slice, so you don't need to repeat yourself.

  2. The reason Rust is complaining is that it is trying to ensure that you do not have read/write aliasing of memory. It is trying to stop you from passing an immutable-borrow of buf into one context and a mutable-borrow of buf into another context.

    • When you say len() is a pure function, I take it you mean that it does not write to any mutable state. However, in the general case, it could be reading mutable state. (That is not the case here, since we are dealing with a fixed size buffer. But still, in general one could imagine that we are dealing with some auto-resizing array abstraction.)

    • So there is an effect, just one that people do not often think about: that of reading.

    • I suspect the idiomatic way of dealing with the problem you saw (ignoring the fact that the API has changed) would be to avoid having the overlapping borrows of buf, e.g. like so:

      Ok(reader) => { let l = buf.len(); reader.read(buf, l) },

This way, you don't repeat yourself; you're just providing two non-overlapping extents where buf is borrowed in different ways.

like image 188
pnkfelix Avatar answered Oct 20 '22 17:10

pnkfelix