I can't find a suitable way to return the exact value of key in a HashMap in Rust . All the existing get methods return in a different format rather than the exact format.
You probably want the HashMap::remove method - it deletes the key from the map and returns the original value rather than a reference:
use std::collections::HashMap;
struct Thing {
content: String,
}
fn main() {
let mut hm: HashMap<u32, Thing> = HashMap::new();
hm.insert(
123,
Thing {
content: "abc".into(),
},
);
hm.insert(
432,
Thing {
content: "def".into(),
},
);
// Remove object from map, and take ownership of it
let value = hm.remove(&432);
if let Some(v) = value {
println!("Took ownership of Thing with content {:?}", v.content);
};
}
The get methods must return a reference to the object because the original object can only exist in one place (it is owned by the HashMap). The remove method can return the original object (i.e "take ownership") only because it removes it from its original owner.
Another solution, depending on the specific situation, may be to take the reference, call .clone() on it to make a new copy of the object (in this case it wouldn't work because Clone isn't implemented for our Thing example object - but it would work if the value way, say, a String)
Finally it may be worth noting you can still use the reference to the object in many circumstances - e.g the previous example could be done by getting a reference:
use std::collections::HashMap;
struct Thing {
content: String,
}
fn main() {
let mut hm: HashMap<u32, Thing> = HashMap::new();
hm.insert(
123,
Thing {
content: "abc".into(),
},
);
hm.insert(
432,
Thing {
content: "def".into(),
},
);
let value = hm.get(&432); // Get reference to the Thing containing "def" instead of removing it from the map and taking ownership
// Print the `content` as in previous example.
if let Some(v) = value {
println!("Showing content of referenced Thing: {:?}", v.content);
}
}
There are two basic methods of obtaining the value for the given key: get() and get_mut(). Use the first one if you just want to read the value, and the second one if you need to modify the value:
fn get(&self, k: &Q) -> Option<&V>
fn get_mut(&mut self, k: &Q) -> Option<&mut V>
As you can see from their signatures, both of these methods return Option rather than a direct value. The reason is that there may be no value associated to the given key:
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert(1, "a");
assert_eq!(map.get(&1), Some(&"a")); // key exists
assert_eq!(map.get(&2), None); // key does not exist
If you are sure that the map contains the given key, you can use unwrap() to get the value out of the option:
assert_eq!(map.get(&1).unwrap(), &"a");
However, in general, it is better (and safer) to consider also the case when the key might not exist. For example, you may use pattern matching:
if let Some(value) = map.get(&1) {
assert_eq!(value, &"a");
} else {
// There is no value associated to the given key.
}
Related
Rust Newbie.
I'd like to create a hashmap that contains values of different types. I got as far as shown, and I can store the values, but I cannot cast them back to the original time when reading them. I'm sure I'm missing something basic, but I'm still struggling with the enum concept in Rust.
#[derive(Debug)]
struct My1 { value: i32 }
#[derive(Debug)]
struct My2 { value: String }
#[derive(Debug)]
enum MyValueType {
MyOne(Vec<My1>),
MyTwo(Vec<My2>)
}
fn main() {
use std::collections::HashMap;
let mut map: HashMap<&str, MyValueType> = HashMap::new();
let a1 = vec!(My1 { value: 100 });
let a2 = vec!(My2 { value: "onehundred".into() });
map.insert("one", MyValueType::MyOne(a1));
map.insert("two", MyValueType::MyTwo(a2));
//let b: &Vec<My1> = map.get("one").unwrap().into(); // err
for (key, value) in &map {
println!("{}: {:?}", key, value);
}
let k1: Vec<My1> = *map.get("one").unwrap().into(); // err: type annotation needed
let k2: Vec<My2> = *map.get("two").unwrap().into(); // err: type annotation needed
}
How should I implement this so I can cast the value of type MyValueType back to Vec or Vec as the case may be? Or am I fundamentally wrong on how I'm setting this up in general?
Starting with:
let v = map.get("one");
The hash map will return an option of the enum (Option<MyValueType>). After unwrapping the option, you’re left with the enum.
let v = map.get("one"); // v is MyValueType (specifically MyOne)
This enum has one of the possible values of MyOne or MyTwo, but we don’t yet know which (more specifically — the compiler doesn’t know, even if we can tell just by looking that it’s MyOne). If you want to reach in to MyOne or MyTwo and grab one of the Vecs that are stored there, you need to match against the enum. For example:
match map.get("one").unwrap() {
MyValueType::MyOne(vector) => {
// do something
},
MyValurType::MyTwo => panic!(“unexpected)
}
This intentionally forces you to check that the enum is the value you are expecting before you are able to access to the data within. Typically you won’t know the exact type of the enum when you are writing code (otherwise why use an enum!) which is why this might seem a bit verbose.
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])...
I have a struct that contains various Routers. Mostly hashmaps. But for this specific hashmap, the values are not updating after insertion. There is no delete function. Just an insert function(shown below).
This is the main struct
pub struct Router {
....
web_socket_routes: Arc<RwLock<HashMap<String, HashMap<String, (PyFunction, u8)>>>>,
}
This is a getter
#[inline]
pub fn get_web_socket_map(
&self,
) -> &Arc<RwLock<HashMap<String, HashMap<String, (PyFunction, u8)>>>> {
&self.web_socket_routes
}
This is the insert method
pub fn add_websocket_route(
&mut self,
route: &str,
connect_route: (Py<PyAny>, bool, u8),
close_route: (Py<PyAny>, bool, u8),
message_route: (Py<PyAny>, bool, u8),
) {
let table = self.get_web_socket_map();
let (connect_route_function, connect_route_is_async, connect_route_params) = connect_route;
let (close_route_function, close_route_is_async, close_route_params) = close_route;
let (message_route_function, message_route_is_async, message_route_params) = message_route;
let insert_in_router =
|handler: Py<PyAny>, is_async: bool, number_of_params: u8, socket_type: &str| {
let function = if is_async {
PyFunction::CoRoutine(handler)
} else {
PyFunction::SyncFunction(handler)
};
let mut route_map = HashMap::new();
route_map.insert(socket_type.to_string(), (function, number_of_params));
println!("socket type is {:?} {:?}", table, route);
table.write().unwrap().insert(route.to_string(), route_map);
};
insert_in_router(
connect_route_function,
connect_route_is_async,
connect_route_params,
"connect",
);
insert_in_router(
close_route_function,
close_route_is_async,
close_route_params,
"close",
);
insert_in_router(
message_route_function,
message_route_is_async,
message_route_params,
"message",
);
}
After all the 3 insert_in_router calls, web_socket_routes only contains the insertion of the last insert_in_router call?
I have tried changing the Arc<RwLock< for a generic DashMap but I am still facing the same issues.
Why is this happening?
Your closure unconditionally creates a new inner hashmap each time, which it uses as value in the outer hashmap. However, it inserts it into the outer hashmap under the same key (route.to_string()) all three times, which results in each insert overwriting the previous one(s).
You need to implement a logic that will create a new inner hashmap only if one is missing under that key, otherwise look up the existing one. Then it should insert the value into the inner hashmap, either the freshly created one, or the one looked up. In Rust this is conveniently done using the entry API:
table
.write()
.unwrap()
.entry(route.to_string())
.or_default()
.insert(socket_type.to_string(), (function, number_of_params));
I have a function that does multiple operations on two vectors. The vectors consist of structs that are later converted to tuples etc....
What I would like is to change the value of a struct in vector 1 by reference, so that the value in vector 1 is equal to the value in vector 2.
When you run the program, you will better see, what I mean.
You'll get the following two output lines:
new_rows after: IndexSet { rows: [IndexRow { is_old_idx: false, hash: "1", value: [], name: "", viewentry_id: "yyy" }] }
old_rows after: IndexSet { rows: [IndexRow { is_old_idx: true, hash: "1", value: [], name: "", viewentry_id: "xxx" }] }
And what I would like is that in new_rows_after.rows.viewentry_id there is also an "xxx". But it still contains the original value "yyy".
At some point I don't seem to pass the reference correctly, but I just can't find the place.
Is there perhaps an experienced Rust expert here who can see where the error might be?
Thanks for your help.
Playground link
If I may say that, your code is pretty messy. I mean, if you want us to help you, you could at least try to make it easier for us to help. One thing that generally helps is: try to reduce the length of your example code. Maybe this can help you to come up with a minimal version of your code in the future: http://blog.pnkfx.org/blog/2019/11/18/rust-bug-minimization-patterns/
(it is actually about minimal code examples for ICE, but minimizing Rust examples is really a general thing, if you ask me).
Problem
Now, to the actual problem. I don't really understand your full example code, so what I did, I just reduce it from a whooping 194 lines down to 43 lines, just keeping, what I assume, is your actual problem.
Also, I found your variable names rather confusing. I mean, what I understand that your problem is about, is that new should have the value from old but instead new has its old value instead of the new value of old -- seriously, that is just confusing. So, I went with a simple foo and bar, and here we go:
fn main() {
let dummy_foo = vec![IndexRow {
id: "good".to_string(),
}];
let dummy_bar = vec![IndexRow {
id: "bad".to_string(),
}];
let set_foo = IndexSet { rows: dummy_foo };
let mut set_bar = IndexSet { rows: dummy_bar };
// Should copy ids from set_foo to set_bar
copy_ids(&mut set_bar, &set_foo);
// Here set_bar still contains "bad"
println!("set_bar: {:?}", set_bar);
}
#[derive(Debug)]
pub struct IndexRow {
pub id: String,
}
#[derive(Debug)]
pub struct IndexSet {
pub rows: Vec<IndexRow>,
}
/// Copy ids from `src` to `dest`
pub fn copy_ids<'a, 'b>(dest: &'a mut IndexSet, src: &'b IndexSet) {
// Create tuples each with a dest and src entry
let mut tuples: Vec<(&str, &str)> = dest
.rows
.iter()
.zip(src.rows.iter())
.map(|(d, s)| (d.id.as_str(), s.id.as_str()))
.collect();
for t in tuples.iter_mut() {
let (ref mut dest_id, src_id) = t;
// Override dest with src
*dest_id = *src_id;
}
}
playground
Now as I understand it, in this above version, the issue is just that the id in set_bar should be replaced with the id in set_foo, but instead set_bar still contains the old "bad" as it is printed at the end of main.
Solution
Assuming that this in deed the case: the problem is rather simple. You need to actually change the id, which is a String. However, in the tuples variable, you have only immutable (&) strs. Therefore, *dest_id = *src_id just replaces the one reference with another and all that is only stored/modified within tuples. The actual String is never touched, it is not even accessible as such from tuples.
So, what you need to do is: get your self access to a modifiable (&mut) String and then modify that string directly. Here you can either replace the entire string e.g. with *dest_id = src_id.to_string(), or if you want to make sure that you really have a String on the left-hand side, you can call a function on it that only exists on String and not on str like dest_id.replace_range(.., src_id).
So, this version of copy_ids does what it should do:
/// Copy ids from `src` to `dest`
pub fn copy_ids<'a, 'b>(dest: &'a mut IndexSet, src: &'b IndexSet) {
// Create tuples each with a dest and src entry
let tuples: Vec<(&mut String, &str)> = dest
.rows
.iter_mut()
.zip(src.rows.iter())
.map(|(d, s)| (&mut d.id, s.id.as_str()))
.collect();
// Override dest with src
for (dest_id, src_id) in tuples.into_iter() {
// Replace the content of the String
dest_id.replace_range(.., src_id);
}
}
full example on playground
Is there a enum/trait for owned values in general, for when you don't want to specify how exactly the value is owned (either shared or not), but you just want to own it.
I need to store references to closures in a struct, which means that they have to live as long as the struct lives. I can't copy them, of course, so they need to be references. But I don't want to make restrictions, so the user of the struct should be able to choose how they want to transfer the ownership.
This is a general problem when you can't copy the values or if they are really big.
Very general example, what I am looking for is this Owned<T>
struct Holder<T> {
value: Owned<T>,
}
...
let rc = Rc::new(variable);
let holder = Holder::new(rc.clone());
let holder2 = Holder::new(Box::new(variable2));
An example for a very easy "implementation" of this type would be:
enum Owned<T> {
Unique(Box<T>),
Shared(Rc<T>),
}
I hope I could explain what I mean.
I think you might be a bit tripped up by the word "owns", which is understandable in Rust! Every value is owned by something, but sometimes the value refers to something that you don't own.
In your case, you just need to accept a T. Then Holder will own the T:
use std::rc::Rc;
struct Holder<T> {
value: T,
}
impl<T> Holder<T> {
fn new(v: T) -> Holder<T> {
Holder { value: v }
}
}
fn main() {
let variable = "Hello world".to_owned();
let variable2 = "Hello moon".to_owned();
let rc = Rc::new(variable);
let holder = Holder::new(rc.clone());
let holder2 = Holder::new(Box::new(variable2));
}
Even if you pass a reference to Holder, it will own the reference. It will not own the referred-to item however.