How to use Rust's Peekable? - rust

I'm interested in peeking ahead in a character stream. To my understanding, Peekable would be the way to go. I can't quite figure out how to use it.
First attempt:
fn trawl<I, E>(pk: &mut I) where I: std::iter::Peekable<Result<char, E>> {
loop {
let cur = pk.next();
let nxt = pk.peek();
match (cur, nxt) {
(Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
_ => (),
}
}
}
fn main() {
trawl(&mut std::io::stdio::stdin().chars());
}
This fails to compile with
> rustc /tmp/main.rs
/tmp/main.rs:1:37: 1:73 error: `std::iter::Peekable` is not a trait
/tmp/main.rs:1 fn trawl<I, E>(pk: &mut I) where I: std::iter::Peekable<Result<char, E>> {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
Okay, fair enough. I don't fully understand traits yet so I try to pass an iterator in and then create a peekable version:
fn trawl<I, E>(it: &mut I) where I: Iterator<Result<char, E>> {
let mut pk = it.peekable();
loop {
let cur = pk.next();
let nxt = pk.peek();
match (cur, nxt) {
(Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
_ => (),
}
}
}
fn main() {
trawl(&mut std::io::stdio::stdin().chars().peekable());
}
This fails with
> rustc /tmp/main.rs
/tmp/main.rs:2:18: 2:20 error: cannot move out of dereference of `&mut`-pointer
/tmp/main.rs:2 let mut pk = it.peekable();
^~
/tmp/main.rs:7:65: 7:70 error: cannot move out of dereference of `&`-pointer
/tmp/main.rs:7 (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
^~~~~
note: in expansion of format_args!
<std macros>:2:23: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
/tmp/main.rs:7:39: 7:77 note: expansion site
error: aborting due to 2 previous errors
Could someone explain:
why Peekable couldn't appear in the function type for lack of being a trait,
what the compiler means when it says 'move out of dereference of' and
how I might resolve either or both?
A third version
fn trawl<I, E>(mut it: I) where I: Iterator<Result<char, E>> {
let mut pk = it.peekable();
loop {
let cur = pk.next();
let nxt = pk.peek();
match (cur, nxt) {
(Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
// (Some(i), ) => println!("{}", i.ok()),
_ => (),
}
}
}
fn main() {
trawl(std::io::stdio::stdin().chars().peekable());
}
This fails with:
> rustc /tmp/main.rs
/tmp/main.rs:7:65: 7:70 error: cannot move out of dereference of `&`-pointer
/tmp/main.rs:7 (Some(i), Some(nxt_i)) => println!("{} {}", i.ok(), nxt_i.ok()),
^~~~~
note: in expansion of format_args!
<std macros>:2:23: 2:77 note: expansion site
<std macros>:1:1: 3:2 note: in expansion of println!
/tmp/main.rs:7:39: 7:77 note: expansion site
error: aborting due to previous error
I fail to understand what rust is saying to me here, how Iterator.next would have a different return type from Peekable.peek.

Peekable is not a trait and thus cannot be used as a bound, which would suggest that it could mean one of many types. It is a single, specific, concrete type, struct Peekable<A, T>. As you have observed, it’s constructed by calling the peekable() method on an iterator, which changes it to something that is peekable.
Here’s how you’d use it if you just wanted to take an iterator:
fn trawl<I, E>(iter: I) where I: Iterator<Result<char, E>> {
let pk = pk.peekable();
…
}
Note also that the peekable() method takes self by value; you can’t take a mutable reference to an iterator there.
The alternative which is what you were aiming for but which I would be generally less inclined towards, would be to require the argument to be peekable, putting the burden onto the caller, as you had:
fn trawl<I, E>(pk: Peekable<E, I>) where I: Iterator<Result<char, E>> {
…
}

Peekable is actually a struct, not a trait. If you wanted to take a Peekable, you could define your function like this:
fn trawl<E, I>(it: Peekable<I>) where I: Iterator<Result<char, E>> {
...
}
Your second implementation is failing to compile because peek takes self by value (i.e. it consumes the iterator, returning a new one), so you can't call it through a &mut reference. Most code simply takes the iterator by value instead of by reference:
fn trawl<E, I>(it: I) where I: Iterator<Result<char, E>> {
let it = it.peekable();
...
}
If you don't want to move the iterator into a function like trawl, you can use the by_ref() method to create a new iterator that holds onto an &mut reference:
let mut my_iterator = /* whatever */;
trawl(my_iterator.by_ref());
// my_iterator is still usable here
As far as style goes, I would say that the second form is the better way to go, as the first leaks what's basically an implementation detail.

Rust has changed a bit since the previous answers. The way to do it now is:
fn trawl<I, E>(pk: Peekable<I>)
where I: Iterator<Item = Result<char, E>> {
…
}

Related

Hashmap multiple mutable borrow issue after reference drop

I am trying to pass around a HashMap which stores values through a set of nested enums/structs. The problem of multiple mutability happens during iteration, even all references should be dropped.
The general idea is to have a vector of values, iterate through them and simplify them, keeping track of them within the HashMap. There are two stages of simplification.
The general flow looks something like
run(Vec<ComplexVal>)
-for each val->
val.fix_complex(holder)
-for each `smp` SimpleVal in val->
basicval = Simplifier::step(smp, holder)
holder.insert("name", basicval)
But the problem is that the holder is borrowed mutably in each stage, and there isn't supposed to be any reference from the ComplexVal to the holder and since the borrowchecker doesn't like multiple borrows, it fails.
Full playground snippet: here
It happens in this snippet:
pub fn run(&mut self, mut vals: Vec<ComplexVal>) {
let mut holder = Holder{hold:HashMap::new()};
// .. setup holder code omitted
let len = vals.len();
for _ in 0..len {
let mut val = vals.remove(0); // remove from vec, should drop after running
println!("Running {:?}", val);
match val {
ComplexVal::Cmplx1(mut c) => {
c.fix_complex(&mut holder)
},
//... more cases of different types of values omitted for simplicity
}
// val *should* be dropped here, and therefore the mutable borrow of holder?
}
println!("Holder: {:?}", holder);
}
}
The only thing I can think of is that it somehow is related to the BasicVal::Ref(&BasicVal) value when created.
I need to return a reference of type &BasicVal so I can't use a regular fn() -> &BasicVal as the reference would be dangling, so I pass a ret value which is to be modified and used as the storage for the return value.
I have also tried just returning the enum BasicVal::Ref(&BasicVal), but run into the same mutability issues.
The example below is a much more simple version which (sort of) demonstrates the same error, just thought I'd include this context in case someone has another idea on how to implement this which wouldn't have these issues
Code (edited)
Updated playground link
Edit: I made a mistake in not needing the lifetimes of both holder and ret to explicitly be the same, so I have made an updated example for it
use std::borrow::BorrowMut;
///////////////////////////////
use std::cell::{RefCell, RefMut};
use std::collections::HashMap;
#[derive(Debug)]
enum BasicVal<'a> {
Ref(&'a BasicVal<'a>),
Val1(BasicStruct),
}
#[derive(Debug)]
struct Holder<'b> {
hold: HashMap<String, RefCell<BasicVal<'b>>>,
}
#[derive(Debug)]
struct BasicStruct {
val: i32,
}
impl<'a> BasicVal<'a> {
pub fn empty() -> Self { BasicVal::Val1(BasicStruct { val: 0 }) }
}
// must match sig of modify_val_ref
fn modify_val<'f>(holder: &'f mut Holder<'f>, mut ret: RefMut<BasicVal<'f>>) {
*ret = BasicVal::Val1(BasicStruct { val: 5 });
}
// must match sig of modify_val
fn modify_val_ref<'f>(holder: &'f mut Holder<'f>, mut ret: RefMut<BasicVal<'f>>) {
ret = holder.hold.get("reference_val").unwrap().borrow_mut();
}
fn do_modify<'f>(holder: &'f mut Holder<'f>) {
let mut v = RefCell::new(BasicVal::empty());
println!("Original {:?}", v);
modify_val(holder, v.borrow_mut());
holder.hold.insert("Data".to_string(), v);
println!("Modified {:?}", holder.hold.get("Data"));
}
pub fn test_dropborrow() {
let mut holder = Holder { hold: HashMap::new() };
holder.hold.insert(
"reference_val".to_string(),
RefCell::new(BasicVal::Val1(BasicStruct { val: 8 })),
);
do_modify(&mut holder);
}
pub fn main() {
test_dropborrow();
}
Edit: Using just the holder for a temp return value gives me a multiple mutable borrow issue, so that workaround doesn't work. I have also tried it with a RefCell with the same issue.
fn modify_val<'f>(holder: &'f mut Holder<'f>) {
holder.hold.insert("$return".to_string(), BasicVal::Val1(BasicStruct{val: 5}));
}
fn do_modify<'f>(holder: &'f mut Holder<'f>) {
modify_val(holder);
let mut v = holder.hold.remove("$return").unwrap();
holder.hold.insert("Data".to_string(), v);
println!("Modified {:?}", v);
}
Error:
935 | fn do_modify<'f>(holder: &'f mut Holder<'f>) {
| -- lifetime `'f` defined here
936 |
937 | modify_val(holder);
| ------------------
| | |
| | first mutable borrow occurs here
| argument requires that `*holder` is borrowed for `'f`
938 | let mut v = holder.hold.remove("$return").unwrap();
| ^^^^^^^^^^^ second mutable borrow occurs here
Any help is greatly appreciated!!!
Figured it out, essentially the BasicVal<'a> was causing Holder to mutably borrow itself in successive iterations of the loop, so removing the lifetime was pretty much the only solution

Why can I just pass an immutable reference to BufReader, instead of a mutable reference? [duplicate]

This question already has an answer here:
Why is it possible to implement Read on an immutable reference to File?
(1 answer)
Closed 6 years ago.
I am writing a simple TCP-based echo server. When I tried to use BufReader and BufWriter to read from and write to a TcpStream, I found that passing a TcpStream to BufReader::new() by value moves its ownership so that I couldn't pass it to a BufWriter. Then, I found an answer in this thread that solves the problem:
fn handle_client(stream: TcpStream) {
let mut reader = BufReader::new(&stream);
let mut writer = BufWriter::new(&stream);
// Receive a message
let mut message = String::new();
reader.read_line(&mut message).unwrap();
// ingored
}
This is simple and it works. However, I can not quite understand why this code works. Why can I just pass an immutable reference to BufReader::new(), instead of a mutable reference ?
The whole program can be found here.
More Details
In the above code, I used reader.read_line(&mut message). So I opened the source code of BufRead in Rust standard library and saw this:
fn read_line(&mut self, buf: &mut String) -> Result<usize> {
// ignored
append_to_string(buf, |b| read_until(self, b'\n', b))
}
Here we can see that it passes the self (which may be a &mut BufReader in my case) to read_until(). Next, I found the following code in the same file:
fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
-> Result<usize> {
let mut read = 0;
loop {
let (done, used) = {
let available = match r.fill_buf() {
Ok(n) => n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e)
};
match memchr::memchr(delim, available) {
Some(i) => {
buf.extend_from_slice(&available[..i + 1]);
(true, i + 1)
}
None => {
buf.extend_from_slice(available);
(false, available.len())
}
}
};
r.consume(used);
read += used;
if done || used == 0 {
return Ok(read);
}
}
}
In this part, there are two places using the BufReader: r.fill_buf() and r.consume(used). I thought r.fill_buf() is what I want to see. Therefore, I went to the code of BufReader in Rust standard library and found this:
fn fill_buf(&mut self) -> io::Result<&[u8]> {
// ignored
if self.pos == self.cap {
self.cap = try!(self.inner.read(&mut self.buf));
self.pos = 0;
}
Ok(&self.buf[self.pos..self.cap])
}
It seems like it uses self.inner.read(&mut self.buf) to read the data from self.inner. Then, we take a look at the structure of BufReader and the BufReader::new():
pub struct BufReader<R> {
inner: R,
buf: Vec<u8>,
pos: usize,
cap: usize,
}
// ignored
impl<R: Read> BufReader<R> {
// ignored
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(inner: R) -> BufReader<R> {
BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
}
// ignored
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
BufReader {
inner: inner,
buf: vec![0; cap],
pos: 0,
cap: 0,
}
}
// ignored
}
From the above code, we can know that inner is a type which implements Read. In my case, the inner may be a &TcpStream.
I knew the signature of Read.read() is:
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
It requires a mutable reference here, but I only lent it an immutable reference. Is this supposed to be a problem when the program reaches self.inner.read() in fill_buf() ?
Quick anser: we pass a &TcpStream as R: Read, not TcpStream. Thus self in Read::read is &mut & TcpStream, not &mut TcpStream. Read is implement for &TcpStream as you can see in the documentation.
Look at this working code:
let stream = TcpStream::connect("...").unwrap();
let mut buf = [0; 100];
Read::read(&mut (&stream), &mut buf);
Note that stream is not even bound as mut, because we use it immutably, just having a mutable reference to the immutable one.
Next, you could ask why Read can be implemented for &TcpStream, because it's necessary to mutate something during the read operation.
This is where the nice Rust-world 🌈 ☮ ends, and the evil C-/operating system-world starts 😈. For example, on Linux you have a simple integer as "file descriptor" for the stream. You can use this for all operations on the stream, including reading and writing. Since you pass the integer by value (it's also a Copy-type), it doesn't matter if you have a mutable or immutable reference to the integer as you can just copy it.
Therefore a minimal amount of synchronization has to be done by the operating system or by the Rust std implementation, because usually it's strange and dangerous to mutate through an immutable reference. This behavior is called "interior mutability" and you can read a little bit more about it...
in the cell documentation
in the book 📖

How to solve this lifetime-related error?

Say I have the following,
type EpollEventCallback<'a> = FnMut(c_int) + Send + Sync + 'a;
struct EpollFdEventHandler<'a> {
on_readable: Option<Box<EpollEventCallback<'a>>>,
on_writable: Option<Box<EpollEventCallback<'a>>>,
}
// Map from c_int -> EpollFdEventHandler.
type EpollEventHandlerMap<'a> = collections::HashMap<c_int, EpollFdEventHandler<'a>>;
fn add_fd_handler
<'a, T: Fn(bool, &'a mut EpollFdEventHandler<'a>)>(
map: &'a mut EpollEventHandlerMap<'a>,
fd: c_int,
adder: T)
{
let mut hash_entry: hash_map::Entry<'a, _, _> = map.entry(fd);
match hash_entry {
hash_map::Entry::Occupied(ref mut occ_e) => {
let entry: &mut EpollFdEventHandler<'a> = occ_e.get_mut();
adder(false, entry);
},
hash_map::Entry::Vacant(vac_e) => {
/*
adder(
true,
vac_e.insert(EpollFdEventHandler {
on_readable: None,
on_writable: None,
}),
);
*/
}
};
}
add_fd_handler is supposed to be a helper function for adding an "FD handler"; here, it's going to get passed a closure (adder) that will set either on_readable or on_writable, depending on which handler is being added. add_fd_handler's job is simply doing the hash table lookup, and inserting an empty entry if required. However:
src/event_loop.rs:85:35: 85:48 error: `(hash_entry:std::collections::hash::map::Occupied).0` does not live long enough
src/event_loop.rs:85 hash_map::Entry::Occupied(ref mut occ_e) => {
^~~~~~~~~~~~~
src/event_loop.rs:82:1: 101:2 note: reference must be valid for the lifetime 'a as defined on the block at 82:0...
src/event_loop.rs:82 {
src/event_loop.rs:83 let mut hash_entry: hash_map::Entry<'a, _, _> = map.entry(fd);
src/event_loop.rs:84 match hash_entry {
src/event_loop.rs:85 hash_map::Entry::Occupied(ref mut occ_e) => {
src/event_loop.rs:86 let entry: &mut EpollFdEventHandler<'a> = occ_e.get_mut();
src/event_loop.rs:87 adder(false, entry);
...
src/event_loop.rs:83:67: 101:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 83:66
src/event_loop.rs:83 let mut hash_entry: hash_map::Entry<'a, _, _> = map.entry(fd);
src/event_loop.rs:84 match hash_entry {
src/event_loop.rs:85 hash_map::Entry::Occupied(ref mut occ_e) => {
src/event_loop.rs:86 let entry: &mut EpollFdEventHandler<'a> = occ_e.get_mut();
src/event_loop.rs:87 adder(false, entry);
src/event_loop.rs:88 },
The error about occ_e only shows up if I try to use it with adder(false, entry)! Rust claims occ_e "does not live long enough", but it's only being used right there in that branch of the match, so how can that be?
My best guess presently is that the closure's second arg, as &'a mut is what's the issue here; my reference in occ_e isn't 'a, it's something shorter (the unspecified lifetime on hash_entry, I think, but I don't know how to notate that).
Let the compiler infer the proper lifetime instead:
fn add_fd_handler
<T: Fn(bool, &mut EpollFdEventHandler)>(
map: &mut EpollEventHandlerMap,
fd: c_int,
adder: T)
{
let mut hash_entry = map.entry(fd);
match hash_entry {
hash_map::Entry::Occupied(ref mut occ_e) => {
let entry = occ_e.get_mut();
adder(false, entry);
},
hash_map::Entry::Vacant(vac_e) => {
/*
adder(
true,
vac_e.insert(EpollFdEventHandler {
on_readable: None,
on_writable: None,
}),
);
*/
}
};
}
The problem is that you're letting the caller determine a lifetime for the callback, but you then invoke the callback with a mutable reference to a local variable. The caller couldn't possibly know about the lifetime of that local variable, so the compiler assumes that 'a must outlive the current function. Yet, entry does not outlive the function, which is why you get an error.
The declaration T: Fn(bool, &mut EpollFdEventHandler) is equivalent to T: for<'a, 'b> Fn(bool, &'a mut EpollFdEventHandler<'b>). The for keyword in this context allows you to declare that T must implement Fn for any value of the specified lifetime parameters. This is only valid for lifetime parameters, because different lifetime parameters do not cause multiple versions of a function to be defined, unlike for type parameters.

Creating a simple linked list

I'm having difficulty getting the borrow checker working for a simple iterative linked list builder.
fn main() {
let v = vec![1,5,3,8,12,56,1230,2,1];
let nodes = Vec::<Node>::with_capacity(v.len());
let mut root: Option<&mut Box<Node>> = None;
let mut prev: &Option<&mut Box<Node>> = &None;
for i in v {
let curr = Some(&mut Box::new(Node { value: i, next: None }));
match *prev {
Some(ref mut p) => {
p.next = curr;
prev = &mut p.next;
},
None => {
root = curr;
prev = &mut root;
}
}
}
}
struct Node<'a> {
value: i32,
next: Option<&'a mut Box<Node<'a>>>,
}
The errors I'm receiving when I try to compile:
linked_list.rs:8:30: 8:69 error: borrowed value does not live long enough
linked_list.rs:8 let curr = Some(&mut Box::new(Node { value: i, next: None }));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: in expansion of for loop expansion
linked_list.rs:7:5: 19:6 note: expansion site
linked_list.rs:4:49: 20:2 note: reference must be valid for the block suffix following statement 2 at 4:48...
linked_list.rs:4 let mut root: Option<&mut Box<Node>> = None;
linked_list.rs:5 let mut prev: &Option<&mut Box<Node>> = &None;
linked_list.rs:6
linked_list.rs:7 for i in v {
linked_list.rs:8 let curr = Some(&mut Box::new(Node { value: i, next: None }));
linked_list.rs:9 match *prev {
...
linked_list.rs:8:9: 8:71 note: ...but borrowed value is only valid for the statement at 8:8
linked_list.rs:8 let curr = Some(&mut Box::new(Node { value: i, next: None }));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
linked_list.rs:8:9: 8:71 help: consider using a `let` binding to increase its lifetime
linked_list.rs:8 let curr = Some(&mut Box::new(Node { value: i, next: None }));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
linked_list.rs:10:18: 10:27 error: cannot borrow immutable anonymous field `(prev:core::option::Some).0` as mutable
linked_list.rs:10 Some(ref mut p) => {
^~~~~~~~~
note: in expansion of for loop expansion
linked_list.rs:7:5: 19:6 note: expansion site
linked_list.rs:15:17: 15:28 error: cannot assign to `root` because it is borrowed
linked_list.rs:15 root = curr;
^~~~~~~~~~~
note: in expansion of for loop expansion
linked_list.rs:7:5: 19:6 note: expansion site
linked_list.rs:16:29: 16:33 note: borrow of `root` occurs here
linked_list.rs:16 prev = &mut root;
^~~~
note: in expansion of for loop expansion
linked_list.rs:7:5: 19:6 note: expansion site
linked_list.rs:16:29: 16:33 error: cannot borrow `root` as mutable more than once at a time
linked_list.rs:16 prev = &mut root;
^~~~
note: in expansion of for loop expansion
linked_list.rs:7:5: 19:6 note: expansion site
linked_list.rs:16:29: 16:33 note: previous borrow of `root` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `root` until the borrow ends
linked_list.rs:16 prev = &mut root;
^~~~
note: in expansion of for loop expansion
linked_list.rs:7:5: 19:6 note: expansion site
linked_list.rs:20:2: 20:2 note: previous borrow ends here
linked_list.rs:1 fn main() {
...
linked_list.rs:20 }
^
error: aborting due to 4 previous errors
What I'm trying to go for is fairly simple. We iterate through a Vec, creating a new node on each iteration. If prev is None this must be the start, so we make the root variable take ownership of that first node. If it's not, we update the previous node's next value to point to this node.
I'm new to Rust so I'm not sure where I'm going wrong. My interpretation is that the borrow checker isn't handling this well. It can't infer that the None branch in the match, containing the 'root' assignment, will only ever be called once, causing the two errors about root being borrowed twice. Am I correct?
Is this approach possible in Rust? Is there a more idiomatic way to do this sort of thing?
(A recursive approach is probably much easier but I'd like to complete an iterative one as a learning exercise.)
First of all, you should probably make sure you've read and understood the Rust Book chapters on Ownership and References and Borrowing. Your immediate problem is that you're borrowing things that aren't owned by anything, and will thus just disappear. You also have other problems like trying to mutate through an immutable pointer.
Let's get something that does, at least, work:
fn main() {
let v = vec![1,5,3,8,12,56,1230,2,1];
let mut root: Option<Box<Node>> = None;
for i in v.into_iter().rev() {
root = Some(Box::new(Node { value: i, next: root }));
}
println!("root: {}",
root.map(|n| n.to_string()).unwrap_or(String::from("None")));
}
struct Node {
value: i32,
next: Option<Box<Node>>,
}
impl std::fmt::Display for Node {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let mut cur = Some(self);
let mut first = true;
try!(write!(fmt, "["));
while let Some(node) = cur {
if !first { try!(write!(fmt, ", ")); }
first = false;
try!(write!(fmt, "{}", node.value));
cur = node.next.as_ref().map(|n| &**n);
}
try!(write!(fmt, "]"));
Ok(())
}
}
This constructs a list and shows how you can iteratively display it. Note the complete lack of borrows in the construction code.
I have cheated somewhat, in that I've iterated the vector backwards to construct the list.
The problem with the original code is that, even if you strip out everything that isn't necessary, down to something like this:
let v = vec![1,5,3,8,12,56,1230,2,1];
let mut v = v.into_iter();
let mut root: Option<Box<Node>> = None;
if let Some(i) = v.next() {
root = Some(Box::new(Node { value: i, next: None }));
let mut prev: &mut Box<Node> = root.as_mut().unwrap();
for i in v {
let curr = Some(Box::new(Node { value: i, next: None }));
prev.next = curr;
prev = prev.next.as_mut().unwrap();
}
}
You still end up in a situation where the compiler sees you mutating a thing you've borrowed by a second path. It's not quite smart enough to realise that re-assigning prev doesn't actually create any aliases. On the other hand, if you break the loop into an equivalent recursion:
if let Some(i) = v.next() {
root = Some(Box::new(Node { value: i, next: None }));
fn step<It>(prev: &mut Box<Node>, mut v: It) where It: Iterator<Item=i32> {
if let Some(i) = v.next() {
let curr = Some(Box::new(Node { value: i, next: None }));
prev.next = curr;
step(prev.next.as_mut().unwrap(), v)
}
}
step(root.as_mut().unwrap(), v);
}
Then it's totally fine with it. Sadly, even with optimisations turned on, Rust doesn't perform tail call elimination in this case. So between borrow checker limitations and a lack of guaranteed tail call elimination, this design might be impossible to do in safe code.
I've run into this problem myself; loops and &mut pointers don't always play nicely with one another. You can work around this by switching to RefCell, with its associated runtime cost, although this then complicates iterating over such a list in a loop. Another alternative is to use usizes instead of pointers, and have all the nodes allocated into a Vec somewhere, although that introduces bounds checking overhead.
Failing all that, there's unsafe code, which lets you write more or less exactly what you would write in another language like C or C++, but without Rust's usual safety guarantees.
At the end of the day, writing data structures that are not just wrappers around an existing data structure in safe Rust without overhead is borderline impossible. It's why the fundamental data structures in Rust are all written using some amount of unsafe code.

Why is a borrow still held in the else block of an if let?

Why does the call self.f2() in the following code trip the borrow checker? Isn't the else block in a different scope? This is quite a conundrum!
use std::str::Chars;
struct A;
impl A {
fn f2(&mut self) {}
fn f1(&mut self) -> Option<Chars> {
None
}
fn f3(&mut self) {
if let Some(x) = self.f1() {
} else {
self.f2()
}
}
}
fn main() {
let mut a = A;
}
Playground
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:16:13
|
13 | if let Some(x) = self.f1() {
| ---- first mutable borrow occurs here
...
16 | self.f2()
| ^^^^ second mutable borrow occurs here
17 | }
| - first borrow ends here
Doesn't the scope of the borrow for self begin and end with the self.f1() call? Once the call from f1() has returned f1() is not using self anymore hence the borrow checker should not have any problem with the second borrow. Note the following code fails too...
// ...
if let Some(x) = self.f1() {
self.f2()
}
// ...
Playground
I think the second borrow should be fine here since f1 and f3 are not using self at the same time as f2.
I put together an example to show off the scoping rules here:
struct Foo {
a: i32,
}
impl Drop for Foo {
fn drop(&mut self) {
println!("Foo: {}", self.a);
}
}
fn generate_temporary(a: i32) -> Option<Foo> {
if a != 0 { Some(Foo { a: a }) } else { None }
}
fn main() {
{
println!("-- 0");
if let Some(foo) = generate_temporary(0) {
println!("Some Foo {}", foo.a);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(foo) = generate_temporary(1) {
println!("Some Foo {}", foo.a);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(Foo { a: 1 }) = generate_temporary(1) {
println!("Some Foo {}", 1);
} else {
println!("None");
}
println!("-- 1");
}
{
println!("-- 0");
if let Some(Foo { a: 2 }) = generate_temporary(1) {
println!("Some Foo {}", 1);
} else {
println!("None");
}
println!("-- 1");
}
}
This prints:
-- 0
None
-- 1
-- 0
Some Foo 1
Foo: 1
-- 1
-- 0
Some Foo 1
Foo: 1
-- 1
-- 0
None
Foo: 1
-- 1
In short, it seems that the expression in the if clause lives through both the if block and the else block.
On the one hand it is not surprising since it is indeed required to live longer than the if block, but on the other hand it does indeed prevent useful patterns.
If you prefer a visual explanation:
if let pattern = foo() {
if-block
} else {
else-block
}
desugars into:
{
let x = foo();
match x {
pattern => { if-block }
_ => { else-block }
}
}
while you would prefer that it desugars into:
bool bypass = true;
{
let x = foo();
match x {
pattern => { if-block }
_ => { bypass = false; }
}
}
if not bypass {
else-block
}
You are not the first one being tripped by this, so this may be addressed at some point, despite changing the meaning of some code (guards, in particular).
It's annoying, but you can work around this by introducing an inner scope and changing the control flow a bit:
fn f3(&mut self) {
{
if let Some(x) = self.f1() {
// ...
return;
}
}
self.f2()
}
As pointed out in the comments, this works without the extra braces. This is because an if or if...let expression has an implicit scope, and the borrow lasts for this scope:
fn f3(&mut self) {
if let Some(x) = self.f1() {
// ...
return;
}
self.f2()
}
Here's a log of an IRC chat between Sandeep Datta and mbrubeck:
mbrubeck: std:tr::Chars contains a borrowed reference to the string that created it. The full type name is Chars<'a>. So f1(&mut self) -> Option<Chars> without elision is f1(&'a mut self) -> Option<Chars<'a>> which means that self remains borrowed as long as
the return value from f1 is in scope.
Sandeep Datta: Can I use 'b for self and 'a for Chars to avoid this problem?
mbrubeck: Not if you are actually returning an iterator over something from self. Though if you can make a function from &self -> Chars (instead of &mut self -> Chars) that would fix the issue.
As of Rust 2018, available in Rust 1.31, the original code will work as-is. This is because Rust 2018 enables non-lexical lifetimes.
A mutable reference is a very strong guarantee: that there's only one pointer to a particular memory location. Since you've already had one &mut borrow, you can't also have a second. That would introduce a data race in a multithreaded context, and iterator invalidation and other similar issues in a single-threaded context.
Right now, borrows are based on lexical scope, and so the first borrow lasts until the end of the function, period. Eventually, we hope to relax this restriction, but it will take some work.
Here is how you can get rid of the spurious errors. I am new to Rust so there may be serious errors in the following explanation.
use std::str::Chars;
struct A<'a> {
chars: Chars<'a>,
}
The 'a here is a lifetime parameter (just like template parameters in C++). Types can be parameterised by lifetimes in Rust.
The Chars type also takes a lifetime parameter. What this implies is that the Chars type probably has a member element which needs a lifetime parameter. Lifetime parameters only make sense on references (since lifetime here actually means "lifetime of a borrow").
We know that Chars needs to keep a reference to the string from which it was created, 'a will probably be used to denote the source string's lifetime.
Here we simply supply 'a as the lifetime parameter to Chars telling the Rust compiler that the lifetime of Chars is the same as the lifetime of the struct A. IMO "lifetime 'a of type A" should be read as "lifetime 'a of the references contained in the struct A".
I think the struct implementation can be parameterised independently from the struct itself hence we need to repeat the parameters with the impl keyword. Here we bind the name 'a to the lifetime of the struct A.
impl<'a> A<'a> {
The name 'b is introduced in the context of the function f2. Here it is used to bind with the lifetime of the reference &mut self.
fn f2<'b>(&'b mut self) {}
The name 'b is introduced in the context of the function f1.This 'b does not have a direct relationship with the 'b introduced by f2 above.
Here it is used to bind with the lifetime of the reference &mut self. Needless to say this reference also does not have any relationship with the &mut self in the previous function, this is a new independent borrow of self.
Had we not used explicit lifetime annotation here Rust would have used its lifetime elision rules to arrive at the following function signature...
//fn f1<'a>(&'a mut self) -> Option<Chars<'a>>
As you can see this binds the lifetime of the reference &mut self parameter to the lifetime of the Chars object being returned from this function (this Chars object need not be the same as self.chars) this is absurd since the returned Chars will outlive the &mut self reference. Hence we need to separate the two lifetimes as follows...
fn f1<'b>(&'b mut self) -> Option<Chars<'a>> {
self.chars.next();
Remember &mut self is a borrow of self and anything referred to by &mut self is also a borrow. Hence we cannot return Some(self.chars) here. self.chars is not ours to give (Error: cannot move out of borrowed content.).
We need to create a clone of self.chars so that it can be given out.
Some(self.chars.clone())
Note here the returned Chars has the same lifetime as the struct A.
And now here is f3 unchanged and without compilation errors!
fn f3<'b>(&'b mut self) {
if let Some(x) = self.f1() { //This is ok now
} else {
self.f2() //This is also ok now
}
}
The main function just for completeness...
fn main() {
let mut a = A { chars:"abc".chars() };
a.f3();
for c in a.chars {
print!("{}", c);
}
}
I have updated the code the make the lifetime relationships clearer.

Resources