1

Running the below code:

extern crate csv;  // csv = "1.0.0-beta.5"

use std::fs::File;

fn main() {
    let file_path = "file.csv";
    let file = File::open(file_path).unwrap();

    let mut rdr = csv::ReaderBuilder::new()
        .has_headers(true)
        .from_reader(file);
    let headers = rdr.headers().unwrap();
    println!("{:?}", headers);

    //println!("{:?}", rdr.headers().unwrap());

    for result in rdr.records() {
        let record = result.unwrap();
        println!("{:?}", record);
    }
}

Results in:

error[E0499]: cannot borrow `rdr` as mutable more than once at a time
  --> src/main.rs:17:19
   |
12 |     let headers = rdr.headers().unwrap();
   |                   --- first mutable borrow occurs here
...
17 |     for result in rdr.records() {
   |                   ^^^ second mutable borrow occurs here
...
21 | }
   | - first borrow ends here

error: aborting due to previous error

If I change these lines:

let headers = rdr.headers().unwrap();
println!("{:?}", headers);

//println!("{:?}", rdr.headers().unwrap());

to the below the code works:

//let headers = rdr.headers().unwrap();
//println!("{:?}", headers);

println!("{:?}", rdr.headers().unwrap());

Similarly if I clone the headers it also works:

let headers = rdr.headers().unwrap().clone();
println!("{:?}", headers);

I read a related question however that question was about a function that the user wrote themselves whereas this use case is where a function was provided by a library.

How should such errors be dealt with and what exactly is happening to cause this error?

Greg
  • 8,175
  • 16
  • 72
  • 125

1 Answers1

0

If you look at headers signature, it is:

fn headers(&mut self) -> Result<&StringRecord>;

So headers() mutably borrows ReaderBuilder's instance. Same for records():

fn records(&mut self) -> StringRecordsIter<R>;

Both of the return types of these functions contains mutable reference(s) to the underlying ReaderBuilder instance.

As per rust's borrow rules, you cannot have multiple mutable references to the same object living at the same time.

Possible mitigation: Use headers() in a separate scope. Thus, the references are dropped, before records() is called.

let mut rdr = csv::ReaderBuilder::new()
    .has_headers(true)
    .from_reader(file);
{
   let headers = rdr.headers().unwrap();
   println!("{:?}", headers);
   // `headers` is dropped here.
}

for result in rdr.records() {
    let record = result.unwrap();
    println!("{:?}", record);
}

The error does not occur when you clone because another brand new object is created and allocated on cloning. You do not have multiple mutable references anymore.

Same, when you use println!("{:?}", rdr.headers().unwrap());, the value returned by headers() is dropped immediately, so the borrow checker does not complain about multiple mutable references.

Whether the functions are provided by a library or created by a user is irrelevant. The only thing that matters is the functions' signatures.

Olivier
  • 773
  • 9
  • 14