I have a bit of code that loads a HashMap and then retrieves a value with the map.get(...) method. In my case, it's possible that I may not be able to return a HashMap, so in reality I'm dealing with an Option<HashMap>.
I've managed to isolate my problem in the following snippet:
use std::collections::HashMap;
type MyMap = HashMap<String, String>;
fn get_map() -> Option<MyMap> {
// In the real case, we may or may not be able to return a map
Some(MyMap::new())
}
fn main() {
let res = get_map().and_then(|h| h.get("foo"));
println!("{:?}", res)
}
I get the following compilation error:
error[E0597]: `h` does not live long enough
--> src/main.rs:11:38
|
11 | let res = get_map().and_then(|h| h.get("foo"));
| ^ - `h` dropped here while still borrowed
| |
| borrowed value does not live long enough
12 | println!("{:?}", res)
13 | }
| - borrowed value needs to live until here
(Playground)
I think that I get what's going on here:
The HashMap owns all of its key-value pairs.
When I call h.get(...) it lends me the value.
Because of that the HashMap needs to exist as long as the value exists.
There are really two questions here:
Am I understanding this correctly?
How do I fix this?
Call Option::as_ref. It converts an Option<T> to Option<&T>:
use std::collections::HashMap;
type MyMap = HashMap<String, String>;
fn get_map() -> Option<MyMap> {
// In the real case, we may or may not be able to return a map
Some(MyMap::new())
}
fn main() {
let map = get_map();
let res = map.as_ref().and_then(|h| h.get("foo"));
println!("{:?}", res)
}
What happened is that and_then consumes the Option; so you were trying to hold a reference to the consumed data.
The same rule applies for the returned value of get_map(): if it is not stored in its own variable, it remains a temporary value, to which you cannot hold a reference.
Related
I'm creating a virtual machine and I'm trying to take two items from the stack. It does it in this order:
PEEK (Get value),
TAKE (Erase from stack),
PEEK (Get value beneath previous value)
However I'm running into an error:
error[E0502]: cannot borrow `self.plate` as mutable because it is also borrowed as immutable
--> src/machine/mod.rs:398:17
|
397 | let apple = self.plate.peek();
| ----------------- immutable borrow occurs here
398 | self.plate.take();
| ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
...
401 | int: apple.value.int,
| --------------- immutable borrow later used here
Been looking for fixes... However, I couldn't find a way to work around this problem. Here's my code:
(machine/mod.rs):
MERGE => {
let apple = self.plate.peek();
self.plate.take();
let banana = self.plate.peek();
let seasoning = GetValueOfType {
int: apple.value.int,
float: 0.0,
str: banana.value.str.clone(),
};
let edible = PackedIngredients {
istype: SupportedTypes::Int,
value: seasoning,
};
}
(plate/mod.rs)
// This function is really internal since it has no use in instructions.
pub fn peek(&self) -> &Food { return self.area.last().unwrap(); }
// Taken't?
pub fn take(&mut self) {
if self.area.len() == 0 {
panic!("\u{001b}[31mUser attempted to take from an empty plate.\u{001b}[0m")
}
self.area.pop();
return; // Swapped to prevent E0308.
}
(Plate is just the stack)
Tried making the peek function &mut self, but that creates more problems since you can only have one mutable in given area.
Studying various guides online, borrowing, immuts, muts, but couldn't find anything that fits / solves my problem.
You're making an immutable borrow here:
let apple = self.plate.peek();
This is because you're taking an immutable reference to self &self and returning &Food, the borrow checker is not that smart to figure out the &Food doesn't belong to &self and can only assume that you borrowed part of &self.
Then you tried to use mutate self.plate, the problem here is after that you used the apple reference int: apple.value.int which means that apple can't be dropped until that line, which results in the error.
There is 2 solutions to this problem:
Return the struct itself and not a reference
pub fn peek(&self) -> Food { return self.area.last().unwrap(); }
Or let apple get dropped before you call self.plate.peek()
let apple = self.plate.peek();
// since integer is a Copy then this will copy the int value
let int = apple.value.int;
// `apple` will be dropped here since it is no longer use after
self.plate.take();
let banana = self.plate.peek();
let seasoning = GetValueOfType {
int,
float: 0.0,
str: banana.value.str.clone(),
};
I have a very simple case where I have some function that takes a Option<Vec>, it then needs to look at that option, and if it is a None, then have a empty byte string, but if it is a Some, then call a function that does some transofmration of it's input.
Sketched out, it looks like this:
pub fn transform(ad: &[u8]) -> Vec<u8> {
ad.to_vec()
}
pub fn func(plaintext: Option<Vec<u8>>) {
let out = "".as_bytes();
if plaintext != None {
let out = transform(&plaintext.unwrap());
}
}
Doing the unwrapping and the if like this is really ugly though,and I would much like to do this in a safer way, maybe with pattern matching:
pub fn transform(ad: &[u8]) -> Vec<u8> {
ad.to_vec()
}
pub fn func(plaintext: Option<Vec<u8>>) {
let out = match plaintext {
Some(x) => &transform(&x),
None => "".as_bytes()
};
}
But this gives the error:
|
16 | let out = match plaintext {
| --- borrow later stored here
17 | Some(x) => &return_smth(&x),
| ^^^^^^^^^^^^^^-
| | |
| | temporary value is freed at the end of this statement
| creates a temporary which is freed while still in use
|
= note: consider using a `let` binding to create a longer lived value
I am unsure about which value that is being talked about here. How do I call my function, and get a slice returned?
I am unsure about which value that is being talked about here.
The one that's returned by transform (or return_smth, or whatever else you call it): that returns a Vec (which is an owned value), you immediately borrow it to a slice, but you never actually store the vec, so at the end of the expression it gets dropped and you have a dangling reference.
How do I call my function, and get a slice returned?
There are two main ways:
You don't, would be my first recommendation here. Rust has a container called Cow which stores "an owned value or a reference", which you can use like a normal reference, or convert to an owned value:
let out = match plaintext {
Some(x) => transform(&x).into(),
None => b"".into(),
};
The second possibility is to store the owned at the highest level you need it, then create a local borrow to that e.g.
let mut _v;
let out = match plaintext {
Some(x) => {
_v = transform(&x);
&*_v
},
None => b"",
};
This is a relatively common pattern for non-trivial code paths where you need to borrow part of the owned value rather than the entirety of it.
Incidentally,
as you can see above Rust has bytes literals (b""), no need to create a string then byteify it
as jmb commented, Rust has high-level methods for common generic tasks. Both "apply transformation to option's value" and "get value or return default" are such
Vec::new() is guaranteed not to allocate, so creating an empty Vec (or String) is not a big deal.
Hence if you don't have a very strong reason to favor a slice
let out = plaintext
.as_deref()
.map_or_else(Vec::new, transform);
would be perfectly fine here, or even
let out = plaintext.map_or_else(Vec::new, transform);
if you change transform to take and return a Vec.
I'm trying to make a code that returns the mode of a list of given numbers.
Here's the code :
use std::collections::HashMap;
fn mode (vector: &Vec<i32>) -> Vec<&&i32> {
let mut occurrences = HashMap::new();
let mut n= Vec::new();
let mut mode = Vec::new();
for i in vector {
let j= occurrences.entry(i).or_insert(0);
*j+=1;
}
for (num, occ) in occurrences.clone().iter() {
if occ> n[0] {
n.clear();
mode.clear();
n.push(occ);
mode.push(num);
} else if occ== n[0] {
mode.push(num);
}
}
mode
}
fn main () {
let mut numbers: Vec<i32>= vec![1,5,2,2,5,3]; // 2 and 5 are the mode
numbers.sort();
println!("the mode is {:?}:", mode(&numbers));
}
I used a vector for the mode since a dataset could be multimodal.
Anyway, I'm getting the following error:
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:26:5
|
13 | for (num, occ) in occurrences.clone().iter() {
| ------------------- temporary value created here
...
26 | mode
| ^^^^ returns a value referencing data owned by the current function
When you return from the current function, any owned values are destroyed (other than the ones being returned from the function), and any data referencing that destroyed data therefore cannot be returned, e.g.:
fn example() -> &str {
let s = String::from("hello"); // owned data
&s // error: returns a value referencing data owned by the current function
// you can imagine this is added by the compiler
drop(s);
}
The issue you have comes from iter(). iter() returns an iterator of shared references:
let values: Vec<i32> = vec![1, 2, 3];
for i in values.iter() {
// i is a &i32
}
for i in values {
// i is an i32
}
So when you call occurrences.clone().iter() you're creating a temporary value (via clone()) which is owned by the current function, then iterating over that data via shared reference. When you destructure the tuple in (num, occ), these are also shared references.
Because you later call mode.push(num), Rust realizes that mode has the type Vec<&i32>. However, there is an implicit lifetime here. The lifetime of num is essentially the lifetime of the current function (let's call that 'a), so the full type of mode is Vec<&'a i32>.
Because of that, you can't return it from the current function.
To fix
Removing iter() should work, since then you will be iterating over owned values. You might also find that you can remove .clone() too, I haven't looked too closely but it seems like it's redundant.
A couple of other points while you're here:
It's rare to interact with &Vec<Foo>, instead it's much more usual to use slices: &[Foo]. They're more general, and in almost all cases more performant (you can still pass your data in like: &numbers)
Check out clippy, it has a bunch of linter rules that can catch a bunch of errors much earlier, and usually does a good job explaining them: https://github.com/rust-lang/rust-clippy
I've very recently started studying Rust, and while working on a test program, I wrote this method:
pub fn add_transition(&mut self, start_state: u32, end_state: u32) -> Result<bool, std::io::Error> {
let mut m: Vec<Page>;
let pages: &mut Vec<Page> = match self.page_cache.get_mut(&start_state) {
Some(p) => p,
None => {
m = self.index.get_pages(start_state, &self.file)?;
&mut m
}
};
// omitted code that mutates pages
// ...
Ok(true)
}
it does work as expected, but I'm not convinced about the m variable. If I remove it, the code looks more elegant:
pub fn add_transition(&mut self, start_state: u32, end_state: u32) -> Result<bool, std::io::Error> {
let pages: &mut Vec<Page> = match self.page_cache.get_mut(&start_state) {
Some(p) => p,
None => &mut self.index.get_pages(start_state, &self.file)?
};
// omitted code that mutates pages
// ...
Ok(true)
}
but I get:
error[E0716]: temporary value dropped while borrowed
--> src\module1\mod.rs:28:29
|
26 | let pages: &mut Vec<Page> = match self.page_cache.get_mut(&start_state) {
| _____________________________________-
27 | | Some(p) => p,
28 | | None => &mut self.index.get_pages(start_state, &self.file)?
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| | | |
| | | temporary value is freed at the end of this statement
| | creates a temporary which is freed while still in use
29 | | };
| |_________- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
I fully understand the error, which directed me to the working snippet, but I'm wondering if there's a more elegant and/or idiomatic way of writing this code. I am declaring m at the beginning of the function, only to prevent a temporary variable from being freed too early. Is there a way of telling the compiler that the lifetime of the return value of self.index.get_pages should be the whole add_transition function?
Further details:
Page is a relatively big struct, so I'd rather not implement the Copy trait nor I'd clone it.
page_cache is of type HashMap<u32, Vec<Page>>
self.index.get_pages is relatively slow and I'm using page_cache to cache results
The return type of self.index.get_pages is Result<Vec<Page>, std::io::Error>
This is normal, your 'cleaner' code basically comes down to do something as follows:
let y = {
let x = 42;
&x
};
Here it should be obvious that you cannot return a reference to x because x is dropped at the end of the block. Those rules don't change when working with temporary values: self.index.get_pages(start_state, &self.file)? creates a temporary value that is dropped at the end of the block (line 29) and thus you can't return a reference to it.
The workaround via m now moves that temporary into the m binding one block up which will live long enough for pages to work with it.
Now for alternatives, I guess page_cache is a HashMap? Then you could alternatively do something like let pages = self.page_cache.entry(start_state).or_insert_with(||self.index.get_pages(...))?;. The only problem with that approach is that get_pages returns a Result while the current cache stores Vec<Page> (the Ok branch only). You could adapt the cache to actually store Result instead, which I think is semantically also better since you want to cache the results of that function call, so why not do that for Err? But if you have a good reason to not cache Err, the approach you have should work just fine.
Yours is probably the most efficient way, but in theory not necessary, and one can be more elegant.
Another way of doing it is to use a trait object in this case — have the variable be of the type dyn DerefMut<Vec<Page>>. This basically means that this variable can hold any type that implements the trait DerefMut<Vec<Page>>>, two types that do so are &mut Vec<Page> and Vec<Page>, in that case the variable can hold either of these, but the contents can only be referenced via DerefMut.
So the following code works as an illustration:
struct Foo {
inner : Option<Vec<i32>>,
}
impl Foo {
fn new () -> Self {
Foo { inner : None }
}
fn init (&mut self) {
self.inner = Some(Vec::new())
}
fn get_mut_ref (&mut self) -> Option<&mut Vec<i32>> {
self.inner.as_mut()
}
}
fn main () {
let mut foo : Foo = Foo::new();
let mut m : Box<dyn AsMut<Vec<i32>>> = match foo.get_mut_ref() {
Some(r) => Box::new(r),
None => Box::new(vec![1,2,3]),
};
m.as_mut().as_mut().push(4);
}
The key here is the type Box<dyn AsMut<Vec<i32>>; this means that it can be a box that holds any type, so long the type implement AsMut<Vec<i32>>, because it's boxed in we also need .as_mut().as_mut() to get the actual &mut <Vec<i32>> out of it.
Because different types can have different sizes; they also cannot be allocated on the stack, so they must be behind some pointer, a Box is typically chosen therefore, and in this case necessary, a normal pointer that is sans ownership of it's pointee will face similar problems to those you face.
One might argue that this code is more elegant, but yours is certainly more efficient and does not require further heap allocation.
In Rust, I have a BTreeSet that I'm using to keep my values in order. I have a loop that should retrieve and remove the first (lowest) member of the set. I'm using a cloned iterator to retrieve the first member. Here's the code:
use std::collections::BTreeSet;
fn main() {
let mut start_nodes = BTreeSet::new();
// add items to the set
while !start_nodes.is_empty() {
let mut start_iter = start_nodes.iter();
let mut start_iter_cloned = start_iter.cloned();
let n = start_iter_cloned.next().unwrap();
start_nodes.remove(&n);
}
}
This, however, gives me the following compile error:
error[E0502]: cannot borrow `start_nodes` as mutable because it is also borrowed as immutable
--> prog.rs:60:6
|
56 | let mut start_iter = start_nodes.iter();
| ----------- immutable borrow occurs here
...
60 | start_nodes.remove(&n);
| ^^^^^^^^^^^ mutable borrow occurs here
...
77 | }
| - immutable borrow ends here
Why is start_nodes.iter() considered an immutable borrow? What approach should I take instead to get the first member?
I'm using version 1.14.0 (not by choice).
Why is start_nodes.iter() considered an immutable borrow?
Whenever you ask a question like this one, you need to look at the prototype of the function, in this case the prototype of BTreeSet::iter():
fn iter(&self) -> Iter<T>
If we look up the Iter type that is returned, we find that it's defined as
pub struct Iter<'a, T> where T: 'a { /* fields omitted */ }
The lifetime 'a is not explicitly mentioned in the definition of iter(); however, the lifetime elision rules make the function definition equivalent to
fn iter<'a>(&'a self) -> Iter<'a, T>
From this expanded version, you can see that the return value has a lifetime that is bound to the lifetime of the reference to self that you pass in, which is just another way of stating that the function call creates a shared borrow that lives as long as the return value. If you store the return value in a variable, the borrow lives at least as long as the variable.
What approach should I take instead to get the first member?
As noted in the comments, your code works on recent versions of Rust due to non-lexical lifetimes – the compiler figures out by itself that start_iter and start_iter_cloned don't need to live longer than the call to next(). In older versions of Rust, you can artificially limit the lifetime by introducing a new scope:
while !start_nodes.is_empty() {
let n = {
let mut start_iter = start_nodes.iter();
let mut start_iter_cloned = start_iter.cloned();
start_iter_cloned.next().unwrap()
};
start_nodes.remove(&n);
}
However, note that this code is needlessly long-winded. The new iterator you create and its cloning version only live inside the new scope, and they aren't really used for any other purpose, so you could just as well write
while !start_nodes.is_empty() {
let n = start_nodes.iter().next().unwrap().clone();
start_nodes.remove(&n);
}
which does exactly the same, and avoids the issues with long-living borrows by avoiding to store the intermediate values in variables, to ensure their lifetime ends immediately after the expression.
Finally, while you don't give full details of your use case, I strongly suspect that you would be better off with a BinaryHeap instead of a BTreeSet:
use std::collections::BinaryHeap;
fn main() {
let mut start_nodes = BinaryHeap::new();
start_nodes.push(42);
while let Some(n) = start_nodes.pop() {
// Do something with `n`
}
}
This code is shorter, simpler, completely sidesteps the issue with the borrow checker, and will also be more efficient.
Not sure this is the best approach, but I fixed it by introducing a new scope to ensure that the immutable borrow ends before the mutable borrow occurs:
use std::collections::BTreeSet;
fn main() {
let mut start_nodes = BTreeSet::new();
// add items to the set
while !start_nodes.is_empty() {
let mut n = 0;
{
let mut start_iter = start_nodes.iter();
let mut start_iter_cloned = start_iter.cloned();
let x = &mut n;
*x = start_iter_cloned.next().unwrap();
}
start_nodes.remove(&n);
}
}