How to delete an element from a HashMap? - rust

I am learning to build a simple CRUD system in Rust, but not sure how to remove an item from the list. Mapping through the list and then when it is matching the item in the todo HashMap, it should delete it from this list.
if action == "remove" {
match todo.remove(&item) {
None => println!("'{}' is not present in the list", item),
Some(_) => match todo.save() {
Ok(_) => println!("todo saved"),
Err(why) => println!("An error occurred: {}", why),
},
}
}
fn remove(&mut self, key: &String) -> Option<()> {
match self.map.get_mut(key) {
Some(v) => Some(v),
None => None,
}
}
Could someone tell me how I can do that in Rust?

Instead of getting a mutable reference to the value in the HashMap, to remove the item you should probably be using the remove method, which returns an Option possibly containing the value that was removed. Assuming that your HashMap is a HashMap<String, Todo>, your remove method could look like this:
fn remove(&mut self, key: &String) -> Option<Todo> {
self.map.remove(key)
}
That being said, a HashSet or other collection could be a better fit for your use case. I would also imagine that you don't want to be saving a todo directly removing it, so your top code block could look like this if you also changed your action to an enum:
match action {
...
Action::Remove(item) => {
match todo.remove(&item) {
Some(value) => println!("{:?} removed from list", value),
None => println!("'{}' is not present in the list", item),
};
},
...
}

Just replace self.map.get_mut(key) with self.map.remove(key)
get_mut: Returns a mutable reference of value related to the exisitng key. Option<&mut V>
remove: deletes the key/value pair and returns the value if key exists. Option<V>

Related

How to update the existing todo item in Rust language

Currently building a CRUD system and want to replace the selected item with the new updated item value. Since I am a noob, still need to learn lot of things, so how can I fix this. Completely confused on how to fix that.
What the current problem is that I am not able to find the item name for example bob and replace that with a new item value.
let action = std::env::args().nth(1).expect("Please provide an action");
let item = std::env::args().nth(2).expect("Please provide an item");
let _getitem = std::env::args().nth(3).expect("Please provide an item");
struct Todo {
map: HashMap<String, bool>,
}
if action == "edit" {
match todo.edit(&item, &_getitem) {
None => println!("'{}' is not present in the list", item),
Some(_) => match todo.save() {
Ok(_) => println!("todo saved"),
Err(why) => println!("An error occurred: {}", why),
},
}
}
fn edit(&mut self, key: &String, value: &String) -> Option<()> {
let elements = self.map.get_mut(key);
elements.push(value.to_string());
}
Data structure of hashmap looks like:
{"bob": true, "new": true }
I assume you want to update an existing record in a HashMap. One way to go about this is using HashMap::entry (Rust Doc):
Once you select an entry you can modify it using the Entry API. This allows you to chain updates and inserts, for example:
let mut map: HashMap<&'static str, usize> = HashMap::new();
map.insert("a", 1);
map
.entry("a")
.and_modify(|val| *val += 1);
In your case edit can look like this:
fn edit(&mut self, key: &String, value: bool) {
self.map.entry(key)
.and_modify(|val| *val = value);
}
Note that in your example the value of a HashMap must be bool but you are trying to update it to a string. You need to parse this first, e.g. using from_str (Rust Doc) or by using your own function:
fn to_bool(s: &str) -> Result<bool, ()> {
if s == "x" {
return Ok(true);
}
if s == "" {
return Ok(false);
}
Err(())
}

How to access nested enums without full match syntax

I am using the Serde crate to deserialise a JSON file, which has a nested structure like this:
struct Nested {
a: Vec<Foo>,
b: u8,
}
struct Foo {
c: Bar,
d: Vec<f32>,
}
Struct Bar {
e: u32,
f: String,
}
Part of the applications purpose is to check for missing parameters (or incorrect types in parameters), and then display a nicely printed list of errors found in the file, so I need to handle the structure missing parameters or wrongly typed.
I came across this great post that helped solved my issue, by wrapping each parameter in an enum result that contains the value if it passed, the value if it failed, or a final enum if it was missing (since the nested structures might also be missing I wrapped them in the same enum):
pub enum TryParse<T> {
Parsed(T),
Unparsed(Value),
NotPresent
}
struct Nested {
a: TryParse<Vec<Foo>>,
b: TryParse<u8>,
}
struct Foo {
c: TryParse<Bar>,
d: TryParse<Vec<f32>>,
}
Struct Bar {
e: TryParse<u32>,
f: TryParse<String>,
}
However, I'm not sure how to access them now without unpacking every step into a match statement. For example, I can access B very easily:
match file.b {
Parsed(val) => {println!("Got parameter of {}", val)},
Unparsed(val) => {println!("Invalid type: {:?}", val)}
NotPresent => {println!("b not found")},
};
However, I'm not sure how to access the nested ones (C D E and F). I can't use Unwrap or expect since this isn't technically a 'Result', so how do I unpack these?:
if file.a.c.e.Parsed() && file.a.c.e == 32 {... //invalid
if file.a.d && file.a.d.len() == 6... //invalid
I know in a way this flies against rust's 'handle every outcome' philosophy, and I want to handle them, but I want to know if there is a nicer way than 400 nested match statements (the above example is very simplified, the files I am using have up to 6 nested layers, each parameter in the top node has at least 3 layers, some are vectors as well)…
Perhaps I need to implement a function similar to unwrap() on my 'TryParse'? or would it be better to wrap each parameter in a 'Result', extend that with the deserialise trait, and then somehow store the error in the Err option that says if it was a type error or missing parameter?
EDIT
I tried adding the following, some of which works and some of which does not:
impl <T> TryParse<T> {
pub fn is_ok(self) -> bool { //works
match self {
Self::Parsed(_t) => true,
_ => false,
}
}
pub fn is_absent(self) -> bool { //works
match self {
Self::NotPresent => true,
_ => false,
}
}
pub fn is_invalid(self) -> bool { //works
match self {
Self::Unparsed(_) => true,
_ => false,
}
}
pub fn get(self) -> Result<T, dyn Error> { //doesnt work
match self {
Self::Parsed(t) => Ok(t),
Self::Unparsed(e) => Err(e),
Self::NotPresent => Err("Invalid")
}
}
}
I can't believe it is this hard just to get the result, should I just avoid nested enums or get rid of the TryParse enums/ functions all together and wrap everything in a result, so the user simply knows if it worked or didn't work (but no explanation why it failed)
Implementing unwrap() is one possibility. Using Result is another, with a custom error type. You can deserialize directly into result with #[serde(deserialize_with = "...")], or using a newtype wrapper.
However, a not-enough-used power of pattern matching is nested patterns. For example, instead of if file.a.c.e.Parsed() && file.a.c.e == 32 you can write:
if let TryParse::Parsed(a) = &file.a {
// Unfortunately we cannot combine this `if let` with the surrounding `if let`,
// because `Vec` doesn't support pattern matching (currently).
if let TryParsed::Parsed(
[Foo {
c:
TryParse::Parsed(Bar {
e: TryParse::Parsed(32),
..
}),
..
}, ..],
) = a.as_slice()
{
// ...
}
}
May not be the most Rust-y way of doing it, but for those like me moving from another language like C/Python/C++, this is the way I have done it that still allows me to quickly validate if I have an error and use the match syntax to handle it. Thanks to #Chayim Friedman for assisting with this, his way is probably better but this made the most sense for me:
#[derive(Debug)]
pub enum TryParse<T> {
Parsed(T),
Unparsed(Value),
NotPresent
}
impl<'de, T: DeserializeOwned> Deserialize<'de> for TryParse<T> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
match Option::<Value>::deserialize(deserializer)? {
None => Ok(TryParse::NotPresent),
Some(value) => match T::deserialize(&value) {
Ok(t) => Ok(TryParse::Parsed(t)),
Err(_) => Ok(TryParse::Unparsed(value)),
},
}
}
}
impl <T> TryParse<T> {
//pub fn is_ok(self) -> bool { ---> Use get().is_ok(), built into result
// match self {
// Self::Parsed(_t) => true,
// _ => false,
// }
//}
pub fn is_absent(self) -> bool {
match self {
Self::NotPresent => true,
_ => false,
}
}
pub fn is_invalid(self) -> bool {
match self {
Self::Unparsed(_) => true,
_ => false,
}
}
pub fn get(&self) -> Result<&T, String> {
match self {
Self::Parsed(t) => Ok(t),
Self::Unparsed(v) => Err(format!("Unable to Parse {:?}", v)),
Self::NotPresent => Err("Parameter not Present".to_string())
}
}
// pub fn get_direct(&self) -> &T {
// match self {
// Self::Parsed(t) => t,
// _ => panic!("Can't get this value!"),
// }
// }
}
match &nested.a.get().unwrap()[1].c.get.expect("Missing C Parameter").e{
Parsed(val) => {println!("Got value of E: {}", val)},
Unparsed(val) => {println!("Invalid Type: {:?}", val)}
NotPresent => {println!("Param E Not Found")},
};
//Note the use of '&' at the beginning because we need to borrow a reference to it
I know I need to change my mindset to use the rust way of thinking, and I am completely open to other suggestions if they can demonstrate some working code.

Access the value of an enum variant

I am working on some language bindings to Arrayfire using the arrayfire-rust crate.
Arrayfire has a typed struct Array<T> which represents a matrix. All acceptable types implement the HasAfEnum trait. This trait has a number of associated types, whose values are not the same for the types that implement this trait.
Since I need a reference to the array in a Rwlock for safe language interop, I have defined the following struct:
pub struct ExAfRef(pub RwLock<ExAfArray>);
impl ExAfRef {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
Self(RwLock::new(ExAfArray::new(slice, dim, dtype)))
}
pub fn value(&self) -> ExAfArray {
match self.0.try_read() {
Ok(refer) => (*refer),
Err(_) => unreachable!(),
}
}
}
which is contained by a struct:
pub struct ExAf {
pub resource: ResourceArc<ExAfRef>,
}
impl ExAf {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
Self {
resource: ResourceArc::new(ExAfRef::new(slice, dim, dtype)),
}
}
// This function is broken
pub fn af_value<T: HasAfEnum>(&self) -> &Array<T> {
self.resource.value().value()
}
}
With the help of the following enum:
pub enum ExAfArray {
U8(Array<u8>),
S32(Array<i32>),
S64(Array<i64>),
F32(Array<f32>),
F64(Array<f64>),
}
impl ExAfArray {
pub fn new(slice: &[u8], dim: Dim4, dtype: ExAfDType) -> Self {
let array = Array::new(slice, dim);
match dtype {
ExAfDType::U8 => ExAfArray::U8(array),
ExAfDType::S32 => ExAfArray::S32(array.cast::<i32>()),
ExAfDType::S64 => ExAfArray::S64(array.cast::<i64>()),
ExAfDType::F32 => ExAfArray::F32(array.cast::<f32>()),
ExAfDType::F64 => ExAfArray::F64(array.cast::<f64>()),
}
}
// This function is broken
pub fn value<T: HasAfEnum>(&self) -> &Array<T> {
// match self {
// ExAfArray::U8(array) => array,
// ExAfArray::S32(array) => array,
// ExAfArray::S64(array) => array,
// ExAfArray::F32(array) => array,
// ExAfArray::F64(array) => array,
// }
if let ExAfArray::U8(array) = self {
return array;
} else if let ExAfArray::S32(array) = self {
return array;
} else if let ExAfArray::S64(array) = self {
return array;
} else if let ExAfArray::F32(array) = self {
return array;
} else {
let ExAfArray::F64(array) = self;
return array;
}
}
pub fn get_type(&self) -> ExAfDType {
match self {
ExAfArray::U8(array) => ExAfDType::U8,
ExAfArray::S32(array) => ExAfDType::S32,
ExAfArray::S64(array) => ExAfDType::S64,
ExAfArray::F32(array) => ExAfDType::F32,
ExAfArray::F64(array) => ExAfDType::F64,
}
}
}
I have used an enum because generic structs are not supported in my language-interop "framework" and because the HasAfEnum trait has associated types (hence dynamic dispatch using dyn is not viable (at least to my knowledge)).
This has worked fine for initializing new arrays.
However when I need to apply some operation on an array, I need to be able to access the value stored by the enum variant. However I am unable to write a type signature for a function to access the value, as dynamic dispatch is not usable and generics are too boilerplate.
Since all variants are tuples, is there some way I can access the value of the tuple variant using a built-in enum feature?
EDIT:
I am using rustler
In short, no there is not a way to do what you seem to be trying to do in Rust presently.
Your functions are broken because you are trying to use generics orthogonally to how they work. When a generic function is called in Rust, the caller fills in the type parameters, not the callee. However, your enum in a sense "knows" what the concrete array type is, so only it can determine what that type parameter is supposed to be. If this mismatch is blocking your progress, this usually calls for a reconsideration of your code structure.
This also explains why there is no built-in enum method that does what you're trying to do. That method would run into the same issue as your value method. When you want to inspect the contents of an enum in Rust, you need to pattern match on it.
There is at least one way to try to accomplish your goal, but I would not really recommend it. One change that makes the code closer to being viable is by passing a closure into the function to make the modification, (the syntax below is not currently valid Rust but it gets the idea across):
pub fn modify<'a, F>(&'a self, op: F)
where
F: for<T: HasAfEnum> FnOnce(&'a Array<T>)
{
// This looks repetitive, but the idea is that in each branch
// the type parameter T takes on the appropriate type for the variant
match self {
ExAfArray::U8(array) => op(array),
ExAfArray::S32(array) => op(array),
ExAfArray::S64(array) => op(array),
ExAfArray::F32(array) => op(array),
ExAfArray::F64(array) => op(array),
}
}
Unfortunately the for<T> FnTrait(T) syntax does not exist yet and I'm not even sure if there's a proposal for it to be added. This can be worked around through a macro:
pub(crate) fn call_unary<F, T, U>(arg: T, f: F) -> U
where F: FnOnce(T) -> U {
f(arg)
}
macro_rules! modify {
($ex_af_array:expr, $op:expr) => {
match &$ex_af_array {
ExAfArray::U8(array) => call_unary(array, $op),
ExAfArray::S32(array) => call_unary(array, $op),
ExAfArray::S64(array) => call_unary(array, $op),
ExAfArray::F32(array) => call_unary(array, $op),
ExAfArray::F64(array) => call_unary(array, $op),
}
};
}
The call_unary helper is needed to ensure type inference works properly. ($op)(array) will fail to compile when the types of the arguments to $op need to be inferred.
Now this solution mostly covers the functionality that for<T> FnTrait(T) would provide, but it's not very clean code (especially after the macro body is sanitized), and the compiler errors will be poor if the macro is misused.

How can I use multi-line match clauses that return values in rust?

For a toy example, say I'd like to make a cache for files on disk and log its output. Here's what I hoped would work:
struct Cache {
data: HashMap<String, String>
}
impl Cache {
fn load(&mut self, filename: &str) -> String {
let result = match self.data.get(filename) {
Some(s) => s.clone(),
None => {
let s = fs::read_to_string(filename).expect("couldn't read");
self.data.insert(String::from(filename), s.clone());
return s;
}
};
println!("my result: {}", result);
return result;
}
}
But the None => {...} clause isn't executed like its own function, so its return exits the whole load function. I tried a couple different ways, but couldn't get multi-line match clauses to return a value. Is there any way to get this type of match working in rust?
rust version: 1.50.0
language edition: 2018
The final statement in a block is returned, that applies to any block, i.e. if you put s as the last line in the None match arm, it will be returned from that block.
You only need to use return when returning from a function or closure.

Matching String: cannot move out of borrowed content

req.url.fragment is an optional String. If it has a value, I want to copy that value into fragment, otherwise I want to assign an empty string. I keep getting the error that I cannot move out of borrowed content.
How do I resolve this?
fn fb_token(req: &mut Request) -> IronResult<Response> {
let fragment = match req.url.fragment {
Some(fragment) => fragment,
None => "".to_string(),
};
Ok(Response::with((status::Ok, fragment)))
}
It depends on what you want to do with the existing string in the structure.
let fragment = match req.url.fragment {
Some(fragment) => fragment,
None => "".to_string(),
};
In this code, you are moving the String out of req.url.fragment, but that would leave it in an undefined state. That's a bad thing, and Rust prevents you from doing that!
As the error message states:
to prevent the move, use ref fragment or ref mut fragment to capture value by reference
If you want to leave the string where it is and return a copy, then you can take a reference and then clone it:
let fragment = match req.url {
Some(ref fragment) => fragment.clone(),
None => "".to_string()
};
If you want to leave the existing string as a None, then you can use take:
let fragment = match req.url.take() {
Some(fragment) => fragment,
None => "".to_string()
};
Even shorter, you can use unwrap_or_else:
let fragment = req.url.take().unwrap_or_else(String::new);
The problem here is that one cannot invalidate a &mut reference, and moving ownership out is one way to invalidate. (There's a few links to similar questions/answers in the sidebar on the right.)
A fix is to instead use references, which should work quite well in this case:
fn fb_token(req: &mut Request) -> IronResult<Response> {
let fragment: &str = match req.url.fragment {
Some(ref fragment) => &**fragment,
None => "",
};
Ok(Response::with((status::Ok, fragment)))
}
(The &str annotation isn't necessary, just to make it clearer what's happening.)
This works because iron implements Modifier<Response> for &str, so that type can be used with with instead of the owned String.

Resources