Rust Iterration over Vector and Ownership [duplicate] - rust

This question already has answers here:
What is the purpose of `&` before the loop variable?
(2 answers)
Closed 3 years ago.
I had been learning Rust recently.
I stumbled across the following code:
pub fn to_bytes(values: &[u32]) -> Vec<u8> {
for &(mut value) in values {
//...
}
}
I do not understand the & in the for loop. What exactly is happening here?
I figured out that if you iterate over a vector, using a for loop, you get a reference (found here):
let v = vec![1, 2, 3];
for value in &v {
// value is a reference
}
Then why do I need another & in the first snipped?

I figured out that if you iterate over a vector, using a for loop, you
get a reference.
This is actually not true. It depends on your vector. If your vector is a reference, it yields a reference. Otherwise it yields an owned value.
Back to your first question:
pub fn to_bytes(values: &[u32]) -> Vec<u8> {
for &(mut value) in values {
// value will be of type u32
//...
}
}
This is called destructuring. Since values here is of type &[u32], the value it yields with the for loop is of type &u32. With the help of &, you dereference the pointer so the value variable here will be of type u32.
Alternatively you can also do the following, but your value will be of type &u32.
pub fn to_bytes(values: &[u32]) -> Vec<u8> {
for mut value in values {
// value will be of type &u32
//...
}
}

Related

Implement `Copy` trait for `Option<Box<Struct>>` [duplicate]

This question already has answers here:
Initialize a large, fixed-size array with non-Copy types
(8 answers)
Closed last month.
I'm trying to implement a simple hash table with external chaining in Rust but having trouble with the table declaration. I declared the table as such:
static mut _HASH_TABLE: [Option<Box<MemoryMap>>; (std::u16::MAX -1) as usize] = [None; (std::u16::MAX -1) as usize];
with the MemoryMap being a dynamic linked list
pub struct MemoryMap {
entry: SimpleEntry,
next: Option<Box<MemoryMap>>,
}
impl MemoryMap {
pub fn new(init_key: String, init_value: Box<dyn Storable>) -> MemoryMap {
MemoryMap {
entry: SimpleEntry::new(init_key, init_value),
next: None,
}
}
//...
}
pub struct SimpleEntry {
key: String,
value: Box<dyn Storable>,
}
impl SimpleEntry {
pub fn new(key: String, value: Box<dyn Storable>) -> SimpleEntry {
SimpleEntry { key, value }
}
//...
}
That said, I get this error
5 | static mut _HASH_TABLE: [Option<Box<MemoryMap>>; (std::u16::MAX -1) as usize] = [None; (std::u16::MAX -1) as usize];
| ^^^^ the trait `Copy` is not implemented for `Box<MemoryMap>`
|
= note: required for `Option<Box<MemoryMap>>` to implement `Copy`
= note: the `Copy` trait is required because this value will be copied for each element of the array
and I can't understand why elements of the arrays have to be copied since I was expecting the array taking ownership of the Box<MemoryMap>
I can't understand why elements of the arrays have to be copied since I was expecting the array taking ownership of the Box<MemoryMap>
When you write
[None; (std::u16::MAX -1) as usize]
the system needs to take the one value you gave it, and duplicate it std::u16::MAX - 1 times in order to fill the array. To do that, it uses Copy:
A repeat expression [x; N], which produces an array with N copies of x. The type of x must be Copy.
That can not work here because even if the None value is trivial, as far as Rust is concerned Option<T> implements Copy iff T implements Copy, and Box<_> does not implement Copy. So you need to implement an alternate initialisation method. Like the one linked by #cafce25, or using once_cell / lazy_static in order to have a global which is (lazy-) initialised at runtime, and would likely be something like a Vec.
Though frankly I don't get why you're even creating a global mutable thing, let alone one initialised a fixed 65k entries (of 64 bit pointers).

Get HashMap back from Entry? [duplicate]

This question already has an answer here:
Returning a reference from a HashMap or Vec causes a borrow to last beyond the scope it's in?
(1 answer)
Closed 3 months ago.
I am implementing a cache which tries a lookup in a table, if that fails it tries a simple method to get the value, and if that fails, it goes and computes multiple new entries in the cache. The Entry system seems specifically designed for the first half of this, but I cannot get the borrow checker to allow me to complete the last half.
use std::collections::HashMap;
fn main() {
let mut cache = Cache { cache: HashMap::new() };
println!("{}", cache.get_from_cache(10));
}
struct Cache {
cache: HashMap<u32, String>
}
impl Cache {
fn get_from_cache<'a>(&'a mut self, i: u32) -> &'a String {
match self.cache.entry(i) {
std::collections::hash_map::Entry::Occupied(entry) => return entry.into_mut(),
std::collections::hash_map::Entry::Vacant(entry) => {
// Some values have an easy way to be computed...
if i == 5 {
return entry.insert("my string".to_string())
}
}
}
// Neither look-up method succeeded, so we 'compute' values one-by-one
for j in 1..=i {
self.cache.insert(j, "another string".to_string()); // Borrow checker fails here
}
self.cache.get(&i).unwrap()
}
}
The problem is that the Entry from self.cache.entry(i) borrows self.cache for the entire lifetime 'a even though I no longer need it at the point that I attempt to do self.cache.insert.
One solution to this (I think) would be if there were a way to turn my reference to the Entry into a reference to its HashMap and then insert through that reference. However, I see no way to do this with the entry interface. Is there some way to achieve this? Or to otherwise satisfy the borrow checker?
This is easily fixed by separating inserting values from returning the final result. You can first make sure the value is in the cache or insert it with some strategy if not, and then return the new value (now guaranteed to be in the HashMap):
fn get_from_cache<'a>(&'a mut self, i: u32) -> &'a String {
// handle inserting the value if necessary:
match self.cache.entry(i) {
std::collections::hash_map::Entry::Occupied(entry) => (),
// Some values have an easy way to be computed...
std::collections::hash_map::Entry::Vacant(entry) if i == 5 => {
entry.insert("my string".to_string());
}
// ... others aren't
std::collections::hash_map::Entry::Vacant(entry) => {
for j in 1..=i {
self.cache.insert(j, "another string".to_string());
}
}
}
// The value is now definitely in `self.cache` so we can return a reference to it
&self.cache[&i]
}

Get last element from vector

I have this simple piece of code:
fn main() {
let mut blockchain: Vec<blockchain::Block> = Vec::new();
let genesis_block = blockchain::create_block("genesis_block");
blockchain::add_block_to_blockchain(&mut blockchain, genesis_block);
}
My error occurs here:
pub fn get_last_block(blockchain: &Vec<Block>) -> Block {
return blockchain[blockchain.len() - 1];
}
It says:
I am pretty new to rust, so can somebody explain me why this wont work?
I just trying to get the last element of this vector.
Should i pass the ownership of this vector instead of borrowing it?
EDIT: This is my result now:
pub fn get_last_block(blockchain: &Vec<Block>) -> Option<&Block> {
return blockchain.last();
}
blockchain could be empty. I check with is_some if its returning an value
let block = blockchain::get_last_block(&blockchain);
if block.is_some() {
blockchain::print_block(block.unwrap());
}
Since you are borrowing the vector, you can either:
return a reference to the block
clone the block
pop the block from the vec and return it (you would need to mutably borrow it instead, &mut)
Also, consider using an Option as return type, in case your vector is empty. By using this, you could directly call to last for example, this would return a reference & to the last Block:
pub fn get_last_block(blockchain: &Vec<Block>) -> Option<&Block> {
blockchain.last()
}
Nitpick, you could use a slice instead of a Vec in the function signature:
fn get_last_block(blockchain: &[Block])...

How to return a reference to a value owned by a Vec within a Rc<RefCell<_>>? [duplicate]

This question already has answers here:
Obtain a reference from a RefCell<Option<Rc<T>>> in Rust
(1 answer)
How do I borrow a RefCell<HashMap>, find a key, and return a reference to the result? [duplicate]
(1 answer)
How do I return a reference to something inside a RefCell without breaking encapsulation?
(3 answers)
Closed 12 months ago.
Assume following code
pub struct Universe {
components: Rc<RefCell<Vec<Component>>>,
active_component: Rc<RefCell<Option<usize>>>,
}
I would like to introduce a convenience method that returns a mutable reference to the active component, e.g.
fn get_active_component(&mut self) -> Option<&mut Component> {
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let i = *active_component_idx;
return self.components.borrow_mut().get_mut(i);
}
Option::None
}
which results in error
145 | return self.components.borrow_mut().get_mut(i);
| ----------------------------^^^^^^^^^^^
| |
| returns a reference to data owned by the current function
| temporary value created here
I do understand the error. The borrow_mut() creates a temporary variable which goes out of scope after the function returns. But I have absolutely no idea how you would realize such a method in rust apart from always inlining the code.
The standard way would be to mimic what RefCell does -- return a proxy struct wrapping the RefMut from .borrow_mut() and containing the vector index, implementing Deref and DerefMut.
pub struct ComponentHandle<'a> {
vecref: RefMut<'a, Vec<Component>>,
index: usize,
}
impl Deref for ComponentHandle<'_> {
type Target = Component;
fn deref(&self) -> &Component {
// SAFETY: We already verified the index is valid, RefCell won't
// dispense another mutable reference while we hold the RefMut, and we
// don't modify the vector's length, so we know this index is valid.
unsafe { self.vecref.get_unchecked(self.index) }
}
}
impl DerefMut for ComponentHandle<'_> {
fn deref_mut(&mut self) -> &mut Component {
// SAFETY: We already verified the index is valid, RefCell won't
// dispense another mutable reference while we hold the RefMut, and we
// don't modify the vector's length, so we know this index is valid.
unsafe { self.vecref.get_unchecked_mut(self.index) }
}
}
impl Universe {
fn get_active_component(&mut self) -> Option<ComponentHandle<'_>> {
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let vecref = self.components.borrow_mut();
let index = *active_component_idx;
if index < vecref.len() {
return Some(ComponentHandle { vecref, index });
}
}
None
}
}
Alternatively, this function could accept a closure to invoke, passing it the bare reference. This is simpler to code, though less idiomatic:
fn get_active_component<F>(&mut self, f: F)
where F: FnOnce(Option<&mut Component>)
{
if let Some(active_component_idx) = self.active_component.borrow().as_ref() {
let i = *active_component_idx;
f(self.components.borrow_mut().get_mut(i));
} else {
f(None);
}
}

Change value in found item [duplicate]

This question already has answers here:
What is the difference between iter and into_iter?
(5 answers)
Closed last month.
I'm trying to find and change a specific item in an iterator like this:
struct ItemType {
name: &'static str,
value: i32
}
struct OuterType {
list: Vec<ItemType>
}
impl OuterType {
pub fn setByName(
self: &mut Self,
name: &str
) -> Result<(), String> {
match self.list.iter().find(|item| item.name == name) {
Some(item_found) => {
item_found.value = 1;
},
None => {
return Err(format!("unrecognized item name (was \"{}\")", name));
}
}
Ok(())
}
}
But this does not compile because of several reasons, some of which:
no Copy trait (don't want to change a copy, I want to change the item in-place);
not borrowed, add & (does not help);
not mutable, add mut (does not help);
cannot assign to item_found.value which is behind a &;
at some point it says & can PROBABLY be removed... (WHAT?);
those errors are cyclic, I'm ping-pong-ing between them with no exit.
I've also tried to .find(|&item| ...).
What is going on? Don't I get to own the value returned by find()? And how am I supposed to change item_found.value? It's just an integer in a struct which is one of several in a vector I get the iterator for.
Just use iter_mut instead of iter when you need to mutate the value:
match self.list.iter_mut().find(...) {...}
Playground

Resources