Understanding try_for_each in RUST? - rust

I am new to Rust and until now I have very hard time understanding the compiler errors. In this specific case I have a fallible function that I want to apply to every element of the iterator. I have try using try_for_each but compiler keeps giving me error the trait bound (): Try is not satisfied . I have no idea how to resolve this issue. I also wonder how people usually get idea of Rust errors, because I feel it is very hard to decode?
Structure of my code is as follows
iter.try_for_each(|x| let some_var= fallible_function(*x)?; do_something_with_var(some_var);)

try_for_each take a closure/function that return a Try type (https://doc.rust-lang.org/std/ops/trait.Try.html), like Option or Result, where you can apply the ? operator, just like you did with fallible_function(*x)?, so if your function return an Result, the closure must return an Result, but your closure end with nothing, so you must return an Infaillible value like Result::Ok (you could return a Residual, https://doc.rust-lang.org/std/ops/trait.FromResidual.html, like Option::None, but the iterator will always return after the first iteration).
I'm entering a bit too much into the detail on how the ? operator work, if you want to know more about the inner working of it and how it can enable you to make your own types for advanced control flow I would highly suggest you to look into the Try trait, but other than that yeah you just need to return Ok(()) or Some(()), depending on what the faillible function return.

Related

rust uwrap_or_else return a reference

I have a situation in a piece of dynamic programming where i either want to get the pre computed results, or call a function to compute these results.
This is the situation in short
let previous_results HashMap<String, Result> = HashMap::new();
for i in some_values {
let result = previous_results.get(i).unwrap_or_else(|| calculate_results(i))
}
The rust compiler justly complains about the function call and it says
expected reference `&HashMap<std::string::String, Result>`
found struct `HashMap<std::string::String, Result>`
This is because .get normally returns a reference to the object,and not the actual object, but the function returns an actual object. So i could just return a reference to what the function returns
let result = previous_results.get(i).unwrap_or_else(|| &calculate_results(i))
Note the &in front of the function call. But this is also an issue, cause a reference to something that is scoped within the anonymous function will be meaningless as soon as the anonymous function returns. And rust complains
cannot return reference to temporary value
returns a reference to data owned by the current function
What am i missing here? What is the correct approach to do this in rust?
You cannot return a reference to a local value (in your case the unwrap_or_else callback), because as that local value is dropped the reference is invalidated.
You could clone the value taken from the map, but that is usually not the most efficient way to go. And maybe the value isn't even cloneable.
So, that is one of the use cases for Cow:
use std::borrow::Cow;
for i in some_values {
let result = previous_results
.get(i)
.map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(calculate_results(i)));
}
And they you use the result more or less normally, as it implements Deref<Result>. But remember that the value inside may be borrowed from the map, so the Cow<'_, Result> value keeps the map borrowed.
Funnily, while the name Cow stands for Clone-On-Write, many times it is used when you need an Owned_Or_Borrowed.
The main drawback of Cow is that it requires the value to be ToOwned, that basically means to implement Clone, because of that C in the name. If your Result type is not Clone, I think that currently there is no solution in std but it is easy to implement your own, or use an available crate such as maybe-owned.
#rodrigo already answered my question with the correct approach, but I was a bit confused of what magic Cow was doing that solved my issue, so i want to clarify for others that might be confused as well.
The crux of the issue for my problem was that .get returns a reference to an element in the HashMap, but the function called by unwrap_or_else needs to return an owned value or it wont be valid once we are outside of the anonymous function scope.
So the solution that is a bit hidden in #rodrigo's answer is the map called after get, which can be used to turn whatever is returned by get into an owned value, so that unwrap_or_else can return an owned value, and the problem is solved.
Cow helps because cloning the value returned by .get is not the most efficient thing to do, unless you do need a copy later on. So Cow abstracts away the ownership and gets .get and unwrap_or_else to return the same type, without having to clone anything.
#rodrigo's answer should still be the accepted answer as it correctly solves the problem, but i wanted to provide a bit more context as i wasn't quite sure how the ownership was resolved.

Why can I access struct fields by a variable and the reference to that variable in the same way? (Rust)

If I print x.passwd, I will get 234
If I print y.passwd, I will get 234 too, But how is that possible since y = &x (essentially storing the address of x), shouldnt I be dereferencing in order to access passwd like (*y).passwd?
I was solving a leetcode problem and they were accessing a node's val field directly by the reference without dereferencing and that made me more confused about references.
On Left hand size, we have Option<Box> while on the right we have &Option<Box>, How can we perform Some(node) = node
PS: I Hope someone explains with a memory diagram of what is actually happening. And if anyone has good resources to understand references and borrowing, Please Let me know, I have been referring the docs and Lets Get Rusty youtube channel but still references are little confusing for me.
In Rust, the . operator will automatically dereference as necessary to find something with the right name. In y.passwd, y is a reference, but references don't have any named fields, so the compiler tries looking at the type of the referent — Cred — and does find the field named passwd.
The same thing works with methods, but there's some more to it — in addition to dereferencing, the compiler will also try adding an & to find a matching method. That way you don't have to write the awkward (&foo).bar() just to call a method that takes &self, similar to how you've already found that you don't have to write (*y).passwd.
In general, you rarely (but not never) have to worry about whether or not something is a reference, when using ..

Rust: Strange syntax with match and variable binding [duplicate]

This question already has an answer here:
How does match compiles with `continue` in its arms?
(1 answer)
Closed last year.
I was looking the Rust's docs where they introduce this piece of code:
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
where the value num is assigned to guess in case of a successful parsing, otherwise the continue statement is executed making the loop to break.
Is it me or this syntax is a bit odd? It feels like we are executing guess = continue. I found this way of writing it more natural:
match guess.trim().parse() {
Ok(num) => let guess: u32 = num,
Err(_) => continue,
};
Am I understanding something wrong? I don't know anything about Rust, so maybe there is an explanation for this.
match is (like amazingly many things in Rust) an expression. So at runtime it has a value that you can assign to a variable, for example.
continue is a control statement. It causes the flow of control to resume at the next iteration of a loop. If that branch is taken, there is no need for a value because the assignment, which would be done after the match, is never executed.
If you are used to other programming languages that have exceptions the following idea may help understanding the situation... in Python, for example, you can assign the return value of a function to a variable:
value = func()
However, if func raises an exception there is no return value. None is needed because execution continues at the nearest exception handler.
Something similar is going on in Rust with control flow commands like continue, break, or return. They basically tell the computer to "forget what you are doing right now, continue with (or leave) the loop/function".
One could argue that the second way feels indeed more natural (it's how you would do it in Python, hehe). However, Rust has very strict scoping rules and it would be hard to define sensibly in which scope the guess variable should exist, or what would happen if another branch defined a different variable. The way it is done in Rust is very clear once you get used to it.
What you have written is not only different from what was given in the example, it is also completely useless.
match can either be used as an expression, or as a statement right away. In the first syntax, you are using match as an expression. Is it odd? Not if you are used to functional programming (for instance, you would have the same pattern in OCaml), but if you come from imperative language it can be a bit puzzling.
In the second case, this does not even mean anything because match arms should be expressions, not statements. So, to make it work, you should at least do something like
match guess.trim().parse() {
Ok(num) => {
let a = num;
}
Err(_) => continue,
}
But then, it's easy to understand what's wrong: the variable a has a lifetime that is less that the match scope, ie. the match scope outlives a, meaning that after the match statement, a is undefined.
See this playground example, where it just does what you expect, as opposed to this playground example which does not even compile. If you look, besides the "this does not make sense" error, there is a "this variable in undefined" error.
Besides, the idea of this pattern is that if you read the code quickly, you start by seeing a let pattern (which is a bit cumbersome), because that is the main point of that statement, and not a conditional flow instruction, because that is not the important part of that statement.

An easy way to find unwrap() usages of Result only

In Rust two of the most commonly used enums, Option and Result, have a method with the same name unwrap(). I'm not sure why Rust authors chose both enums to use the same method name - it's clear that both enums are somewhat similar, but that decision can make it harder to find all the usages of, say, Result's method only. And I think in a Rust project it would be very useful if we could easily find all the places where we have unwrap() or something else that might panic. For example, if we start off with some proof-of-concept implementation that is OK to panic but later decide to properly handle errors.
Option's unwrap() could also panic, of course, but usually we would have made sure that wouldn't be possible, so there is a clear difference, compared to Result, where we generally expect there might be an error. (Also, I know Option's unwrap() can generally be avoided by using alternatives, but sometimes it does make code simpler.)
Update
It seems from the comments I should probably clarify why I said sometimes Option's unwrapping should be considered safe. I guess an example would be best:
if o.is_none() {
// ...
return ...;
}
// ...
o.unwrap() // <--- Here I do NOT expect a None

How do I collect the values of a HashMap into a vector?

I can not find a way to collect the values of a HashMap into a Vec in the documentation. I have score_table: HashMap<Id, Score> and I want to get all the Scores into all_scores: Vec<Score>.
I was tempted to use the values method (all_scores = score_table.values()), but it does not work since values is not a Vec.
I know that Values implements the ExactSizeIterator trait, but I do not know how to collect all values of an iterator into a vector without manually writing a for loop and pushing the values in the vector one after one.
I also tried to use std::iter::FromIterator; but ended with something like:
all_scores = Vec::from_iter(score_table.values());
expected type `std::vec::Vec<Score>`
found type `std::vec::Vec<&Score>`
Thanks to Hash map macro refuses to type-check, failing with a misleading (and seemingly buggy) error message?, I changed it to:
all_scores = Vec::from_iter(score_table.values().cloned());
and it does not produce errors to cargo check.
Is this a good way to do it?
The method Iterator.collect is designed for this specific task. You're right in that you need .cloned() if you want a vector of actual values instead of references (unless the stored type implements Copy, like primitives), so the code looks like this:
all_scores = score_table.values().cloned().collect();
Internally, collect() just uses FromIterator, but it also infers the type of the output. Sometimes there isn't enough information to infer the type, so you may need to explicitly specify the type you want, like so:
all_scores = score_table.values().cloned().collect::<Vec<Score>>();
If you don't need score_table anymore, you can transfer the ownership of Score values to all_scores by:
let all_scores: Vec<Score> = score_table.into_iter()
.map(|(_id, score)| score)
.collect();
This approach will be faster and consume less memory than the clone approach by #apetranzilla. It also supports any struct, not only structs that implement Clone.
There are three useful methods on HashMaps, which all return iterators:
values() borrows the collection and returns references (&T).
values_mut() gives mutable references &mut T which is useful to modify elements of the collection without destroying score_table.
into_values() gives you the elements directly: T! The iterator takes ownership of all the elements. This means that score_table no longer owns them, so you can't use score_table anymore!
In your example, you call values() to get &T references, then convert them to owned values T via a clone().
Instead, if we have an iterator of owned values, then we can convert it to a Vec using Iterator::collect():
let all_scores: Vec<Score> = score_table.into_values().collect();
Sometimes, you may need to specify the collecting type:
let all_scores = score_table.into_values().collect::<Vec<Score>>();

Resources