Rust peekable double reference - rust

Why does a peekable iterator return a double reference in an Option?
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
let next = iter.peek();
next is an Option<&&Foo>, not an Option<&Foo>.
How do I get it to be the latter?
I do not want to use .into_iter() because I do not want to consume the vec. I just want a borrowed reference to the Foo struct wrapped in an Option.

peek yields references to whatever you're iterating over. If that's also references, it'll yield double references. You can use the copied Option adapter to remove that level of indirection:
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
// use `copied` here to go from Option<&&_> to Option<&_>
let next = iter.peek().copied();
Alternatively, you can just call next after you checked that you want the peeked value:
struct Foo {}
let mut foovec = vec![];
foovec.push(Foo {});
let mut iter = foovec.iter().peekable();
if is_okay(iter.peek()) {
let next = iter.next(); // `next` has type `&Foo`
}
You could even use pattern matching to remove one level of indirection:
if let Some(&next) = iter.peek() {
// `next` has type `&Foo` in this block
}

Related

Why do String::from(&str) and &str.to_string() behave differently in Rust?

fn main() {
let string = "Rust Programming".to_string();
let mut slice = &string[5..12].to_string(); // Doesn't work...why?
let mut slice = string[5..12].to_string(); // works
let mut slice2 = String::from(&string[5..12]); // Works
slice.push('p');
println!("slice: {}, slice2: {}, string: {}", slice,slice2,string);
}
What is happening here? Please explain.
The main issue here that & have lower priority than method call.
So, actual code is
let mut slice = &(string[5..12].to_string());
So you a taking a reference to temporary String object that dropped and cannot be used later.
You should wrap your reference in parenthesis and call the method on the result.
fn main() {
let string = "Rust Programming".to_string();
let mut slice = (&string[5..12]).to_string(); // ! -- this should work -- !
let mut slice = string[5..12].to_string(); // works
let mut slice2 = String::from(&string[5..12]); // Works
slice.push('p');
println!("slice: {}, slice2: {}, string: {}", slice,slice2,string);
}

How to move a range of elements from BytesMut?

I have a method that takes a mutable instance of BytesMut. I want to move chunks of it into other instances of BytesMut but am not sure about the syntax to do so. Are there any examples out there?
You could use the range operator on the original buf to move things around or split_off based on some offset value. For example:
use bytes::{BufMut, BytesMut};
fn main() {
let mut buf = BytesMut::with_capacity(64);
let mut buf_to = BytesMut::with_capacity(64);
buf.put_u8(b't');
buf.put_u8(b'e');
buf.put_u8(b's');
buf.put_u8(b't');
// move last 2 elements
buf_to.put(&buf[2..]);
println!("{:#?}", buf_to); // b"st"
// You can also split_off the original value
let mut another_buf = buf.split_off(2);
println!("{:#?}", another_buf); // b"st"
println!("{:#?}", buf); // b"te"
}

Lifetimes of references in mutable Vector

I have an algorithm like:
let seed: Foo = ...
let mut stack: Vec<&Foo> = Vec::new();
stack.push(&seed);
while let Some(next) = stack.pop {
let more_foos: Vec<Foo> = some_function_of(next) // 0 to many Foos returned
for foo in more_foos {
stack.push(&foo);
}
}
I receive the error that foo does not live long enough. I assume this is because stack has a greater lifetime. How can I fix this?
more_foos and its contents are dropped at the end of each iteration of the while let loop. However, you're trying to store a reference to items from more_foos in stack, and that's not valid, as that would lead to dangling pointers.
Instead, you should make stack own Foo objects instead.
fn main() {
let seed: Foo = unimplemented!();
let mut stack: Vec<Foo> = Vec::new();
stack.push(seed);
while let Some(next) = stack.pop() {
let more_foos: Vec<Foo> = unimplemented!();
for foo in more_foos {
stack.push(foo);
}
}
}
Note: the for loop can be replaced with:
stack.extend(more_foos);
which might be slightly more efficient.

How do I modify Rc<RefCell> from inside the closure?

I am trying to pass RefCell to a function in a closure and then modify the same variable from inside the closure. Here is my code:
let path: Rc<RefCell<Option<Vec<PathBuf>>>> = Rc::new(RefCell::new(None));
...
//valid value assigned to path
...
let cloned_path = path.clone();
button_run.connect_clicked(move |_| {
let to_remove: usize = open_dir(&mut cloned_path.borrow_mut().deref_mut());
//Here I need to remove "to_remove" index from cloned_path
});
//Choose a random directory from Vec and open it. Returns opened index.
fn open_dir(path_two: &mut Option<Vec<PathBuf>>) -> usize {
let vec = path_two.clone();
let vec_length = vec.unwrap().len();
let mut rng = thread_rng();
let rand_number = rng.gen_range(0, vec_length);
let p: &str = &*path_two.clone().expect("8")[rand_number].to_str().unwrap().to_string();
Command::new("explorer.exe").arg(p).output();
rand_number.clone()
}
First I thought that since my open_dir() function accepts &mut, I can modify the vector inside the function. But no matter what I tried I kept getting cannot move out of borrowed content error.
Then I thought - ok, I can return the index from the function and access cloned_path from the closure itself. But the only code that I could get to compile is
button_run.connect_clicked(move |_| {
let to_remove: usize = open_dir(&mut cloned_path.borrow_mut().deref_mut());
let x = &*cloned_path.borrow_mut().clone().unwrap().remove(to_remove);
});
It works, but it removes from a cloned version of cloned_path, leaving the original unaffected. Is there a way to access cloned_path directly to modify it's contents and if there is one, how do I approach this task?
The main way to modify contents of an enum value (and Option is enum) is pattern matching:
fn do_something(path_two: &mut Option<Vec<PathBuf>>) {
if let Some(ref mut paths) = *path_two {
paths.push(Path::new("abcde").to_path_buf());
}
}
Note that paths pattern variable is bound with ref mut qualifier - it means that it will be of type &mut Vec<PathBuf>, that is, a mutable reference to the internals of the option, exactly what you need to modify the vector, in case it is present.

Default mutable value from HashMap

Suppose I have a HashMap and I want to get a mutable reference to an entry, or if that entry does not exist I want a mutable reference to a new object, how can I do it? I've tried using unwrap_or(), something like this:
fn foo() {
let mut map: HashMap<&str, Vec<&str>> = HashMap::new();
let mut ref = map.get_mut("whatever").unwrap_or( &mut Vec::<&str>::new() );
// Modify ref.
}
But that doesn't work because the lifetime of the Vec isn't long enough. Is there any way to tell Rust that I want the returned Vec to have the same lifetime as foo()? I mean there is this obvious solution but I feel like there should be a better way:
fn foo() {
let mut map: HashMap<&str, Vec<&str>> = HashMap::new();
let mut dummy: Vec<&str> = Vec::new();
let mut ref = map.get_mut("whatever").unwrap_or( &dummy );
// Modify ref.
}
As mentioned by Shepmaster, here is an example of using the entry pattern. It seems verbose at first, but this avoids allocating an array you might not use unless you need it. I'm sure you could make a generic function around this to cut down on the chatter :)
use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
fn foo() {
let mut map = HashMap::<&str, Vec<&str>>::new();
let mut result = match map.entry("whatever") {
Vacant(entry) => entry.insert(Vec::new()),
Occupied(entry) => entry.into_mut(),
};
// Do the work
result.push("One thing");
result.push("Then another");
}
This can also be shortened to or_insert as I just discovered!
use std::collections::HashMap;
fn foo() {
let mut map = HashMap::<&str, Vec<&str>>::new();
let mut result = map.entry("whatever").or_insert(Vec::new());
// Do the work
result.push("One thing");
result.push("Then another");
}
If you want to add your dummy into the map, then this is a duplicate of How to properly use HashMap::entry? or Want to add to HashMap using pattern match, get borrow mutable more than once at a time (or any question about the entry API).
If you don't want to add it, then your code is fine, you just need to follow the compiler error messages to fix it. You are trying to use a keyword as an identifier (ref), and you need to get a mutable reference to dummy (& mut dummy):
use std::collections::HashMap;
fn foo() {
let mut map: HashMap<&str, Vec<&str>> = HashMap::new();
let mut dummy: Vec<&str> = Vec::new();
let f = map.get_mut("whatever").unwrap_or( &mut dummy );
}
fn main() {}

Resources