Why for_each cannot replace for loop in the code? - rust

My original code is:
const DNA: [char; 4] = ['A', 'C', 'G', 'T'];
...
let mut map: HashMap<char, usize> = HashMap::new();
/* initialize the hashmap */
for d in DNA.iter() {
map.insert(*d, 0);
}
The code was compiled. Then I want to replace the for loop with for_each:
DNA.iter().for_each(|d| map.insert(*d, 0));
Compiling error:
error[E0308]: mismatched types
--> src/lib.rs:26:29
|
26 | DNA.iter().for_each(|d| map.insert(*d, 0));
| ^^^^^^^^^^^^^^^^^ expected `()`, found enum `Option`
|
= note: expected unit type `()`
found enum `Option<usize>`
It seems for_each and for is not totally equivalent? Why doesn't for_each just ignore the return value of map.insert()?

Why doesn't for_each just ignore the return value of map.insert() ?
Because the Rust syntax simply doesn't work that way.
Every function has a return type, omitting it doesn't mean "no return value". That is syntactic sugar for -> (), i.e. a return type of "unit".
Both an explicit return map.insert(*d, 0); and the shorthand of map.insert(*d, 0) without a semicolon at the end of a block are return statements. They are explicitly "do a return here", not an optional "maybe return a value if it might make sense".
Therefore, you're currently trying to provide an Option<V> where the function signature demands a (), which is why you get the error you've shown.
So you'll have to adjust your closure to not return that value (or more specifically, to return the unit type ()):
// the explicit version
DNA.iter().for_each(|d| {
map.insert(*d, 0);
()
});
// the more idiomatic, shorter equivalent
DNA.iter().for_each(|d| { map.insert(*d, 0); });
Notice how the first version does return a value that matches the function signature. The second version is just syntactic sugar, where you can omit a return value of ().

Other answers explain what the problem is, and what the solution is (making the return type ()). However, none mention that there is a function in the standard library, in the prelude, that does exactly this: it's drop. Indeed, drop: fn(T) -> () for any type T, and it doesn't do anything more (it's definition is literally fn drop<T>(_: T) {}).
So, to solve your problem, you can do
DNS.iter().for_each(|d| drop(map.insert(*d, 0)))

fn for_each<F>(self, f: F)where
    Self: Sized,
    F: FnMut(Self::Item)
The above is the function signature of std::iter::for_each. Notice that the constraint F: FnMut(Self::Item) means that it can only be called with a callback function that takes a Self::Item as its input and returns nothing. If you must use for_each for this task, one option is to append a semicolon ; to make the closure return nothing, although this has pretty much the same amount of punctuation as the for ... in version.
DNA.iter().for_each(|d| {
map.insert(*d, 0);
});
std::iter::for_each on Rust documentation

Related

Read file to string, return new strings rather than references?

I use rust to open a file and parse its contents.
let file = fs::read_to_string(file_path).unwrap();
I then iterate over each line:
for item in file.lines() {
// processing
}
at this point item is of type &str. I now need only a slice of that so I:
let string_slice = &item[0..2];
however, string_slice is now of type &&str (two &s). I want to return a vec of strings, however the file I read doesnt need to live longer than the function scope I open it in. I can get to a string by calling to_string() twice; but this seems awkward.
let string_slice = &item[0..2].to_string();
return string_slice.to_string() //have to call twice
is there a more elegant way to pass ownership of these slices to a vec that I then return from the function?
The other answer explains what happens under the hood, but if you want to know the idiomatic way to achieve what you're trying to, this is it:
fn get_lines() -> Vec<String> {
// Replace this with your actual input. You can `expect()` the value
// (instead of `unwrap()`) if you're sure it's there or return a `Result`
// if you're not.
// You can also pass it in as an argument. In that case, the parameter type
// should be `&str` instead of `String`. This is a common mistake among
// beginners.
let sample_input = String::from("one\ntwo\nthree\n");
sample_input
.lines()
// You can use `to_string()`, `to_owned()`, or `into()` to convert a
// string slice into a string. Either works. I find the automatic type
// inference of `into()` most satisfying, but it's up to preference in
// this case.
// The type annotation for `line` is optional.
.map(|line: &str| line[0..2].into())
// Because the function returns a `Vec`, you can omit the type. I.e.,
// you don't have to write `collect::<Vec<_>>()`. It's inferred.
.collect()
}
Run this snippet on Rust Playground.
let string_slice: &str = &item[0..2];
however, string_slice is now of type &&str (two &s).
That's not right, the type of item[0..2] is str so you have to take a reference to use it since it's unsized,
the type of &item[0..2] is then the &str you can work with.
When you directly invoke a method on it like here:
let string_slice: &String = &item[0..2].to_string();
due to auto (de-)referencing the compiler will add an automatic reference to the string slice so it desugars to this:
let string_slice: &String = &( // <- the referen you take explicitly
/*the reference the compiler inserts -> */ (&item[0..2]).to_string()
);
I added an extra pair of parentheses to make the precedence clear. So after this string_slice which is a bit of a misnomer here is of type &String.
To get a String instead you can just remove your manual reference.
let string_slice: String = item[0..2].to_string();
which desugars to
let string_slice: String = (&item[0..2]).to_string();
I've annotated all the types above for ease of understanding, but they're exactly what the compiler would infer for them.
As a tip to get the compiler to tell you what type a variable is if you don't have editor support which can tell you you can always add a type annotation of : () and the compiler will error with a message telling you what it expected the type to be:
let string_slice: () = &item[0..2];
will error with something like the following
error[E0308]: mismatched types
--> src/main.rs:2:17
|
| let string_slice: () = &item[..];
| -- ^^^^^^^^^ expected `()`, found `&str`
| |
| expected due to this
For more information about this error, try `rustc --explain E0308`.

Why can I compare a String to a &str using if, but not when using match?

I'm trying to implement a function that reads command line arguments and compares them to hard-coded string literals.
When I do the comparison with an if statement it works like a charm:
fn main() {
let s = String::from("holla!");
if s == "holla!" {
println!("it worked!");
}
}
But using a match statement (which I guess would be more elegant):
fn main() {
let s = String::from("holla!");
match s {
"holla!" => println!("it worked!"),
_ => println!("nothing"),
}
}
I keep getting an error from the compiler that a String was expected but a &static str was found:
error[E0308]: mismatched types
--> src/main.rs:5:9
|
5 | "holla!" => println!("it worked!"),
| ^^^^^^^^ expected struct `std::string::String`, found reference
|
= note: expected type `std::string::String`
found type `&'static str`
I've seen How to match a String against string literals in Rust? so I know how to fix it, but I want to know why the comparison works when if but not using match.
I want to know why the comparison works when if but not using match.
It's not so much about if and more because you've used == in the condition. The condition in an if statement is any expression of type bool; you just happen to have chosen to use == there.
The == operator is really a function associated with the PartialEq trait. This trait can be implemented for any pair of types. And, for convenience, String has implementations for PartialEq<str> and PartialEq<&str>, among others - and vice versa.
On the other hand, match expressions use pattern matching for comparison, not ==. A &'static str literal, like "holla!", is a valid pattern, but it can never match a String, which is a completely different type.
Pattern matching lets you concisely compare parts of complex structures, even if the whole thing isn't equal, as well as bind variables to pieces of the match. While Strings don't really benefit from that, it's very powerful for other types, and has an entirely different purpose than ==.
Note that you can use pattern matching with if by instead using the if let construct. Your example would look like this:
if let "holla!" = &*s {
println!("it worked!");
}
Conversely, one way to use == inside a match is like this:
match s {
_ if s == "holla!" => println!("it worked!"),
_ => println!("nothing"),
}
Or, as #ljedrz suggested:
match s == "holla!" {
true => println!("it worked!"),
_ => println!("nothing")
}
As #peter-hall said, there's a mismatch of types because match expressions use pattern matching, which is different from the == that are associated with the PartialEq trait.
There a second way to resolve this issue, by casting your String into an &str (a string slice) :
match &s[..] {
"holla!" => println!("it worked!"),
"Hallo!" => println!("with easy to read matches !"),
_ => println!("nothing"),
}

How do I put structs or tuples in state of rust iterators?

I'm very new to Rust. I'm trying to use Advent of Code as an excuse to learn it. I'm currently an Elixir programmer so I use map/reduce all day.
I'm struggling to do the same thing with rust. I'm sure I could just bail on the iterators and just plow through it with for loops but I'd prefer not to.
It looks like fold is something very similar to reduce but I can't figure out how to use any state more complicated than an integer.
input
.chars()
.map(|c| c.to_digit(10).unwrap())
.fold(initial_state, |state, &x| {
let Day1{sum: sum, prev: prev} = state;
Some(Day1{
sum: sum,
prev: prev,
});
})
I'm getting lots of compiler errors about non-matching types.
.fold(initial_state, |state, &x| {
^^^^^^^^^^^^^ expected (), found struct `Day1`
let Day1{sum: sum, prev: prev} = state;
^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found struct `Day1`
Why does it expect () which is nothing (I think). I'd like to understand the error, but if there is a better way to have state maintained in a loop I'd like some help with that as well.
The problem is very clear if you look what you are doing. Let me explain.
First, it is good idea to have the Rust docs in touch. Looking at the std::iter::Iterator::fold method there gives you it's signature:
fn fold<B, F>(self, init: B, f: F) -> B where
F: FnMut(B, Self::Item) -> B,
There are 3 arguments: self which you don't touch because you use this method as a struct method and not static method, init which you set to initial_state and a fold function as f. At a glance you may say everything is correct but your usage mismatches this prototype because of excess semicolon at the end of the fold function - your whole expression returns () in that case and so the compiler tries to match the return type of your fold function with the init argument's type and it is unable to do that. The solution is very simple: remove the semicolon by changing
let Day1 { sum: sum, prev: prev } = state;
Some(Day1 {
sum: sum,
prev: prev,
});
to this:
let Day1 {sum: sum, prev: prev} = state;
Some(Day1 {
sum: sum,
prev: prev,
})
In Rust (as in most functional languages), the last expression is a return expression. In your case, you returned nothing but if you remove the semicolon, you will return the Some(Day1 { sum: sum, prev: prev }) expression which has a type of Option<Day1>.
After fixing this, you may have another problem: mismatching Day1 and Option<Day1> which will occur because you have different types again: initial_state of type Day1 and the fold function which returns Option<Day1>. The solution is to use the same type in any of these places, for example, make initial_state of type Option<Day1> or return Day1 object from the fold function and so everything will compile. Again, having the Rust documentation in touch gives you a clear example of the .fold usage.

Calling a function which takes a closure twice with different closures

As a project for learning rust, I am writing a program which can parse sgf files (a format for storing go games, and technically also other games). Currently the program is supposed to parse strings of the type (this is just an exampel) ";B[ab]B[cd]W[ef]B[gh]" into [Black((0,1)),Black((2,3,)),White((4,5)),Black((6,7))]
For this I am using the parser-combinators library.
I have run into the following error:
main.rs:44:15: 44:39 error: can't infer the "kind" of the closure; explicitly annotate it; e.g. `|&:| {}` [E0187]
main.rs:44 pmove().map(|m| {Property::White(m)})
^~~~~~~~~~~~~~~~~~~~~~~~
main.rs:44:15: 44:39 error: mismatched types:
expected `closure[main.rs:39:15: 39:39]`,
found `closure[main.rs:44:15: 44:39]`
(expected closure,
found a different closure) [E0308]
main.rs:44 pmove().map(|m| {Property::White(m)})
^~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 2 previous errors
Could not compile `go`.
The function in question is below. I am completely new to rust, so I can't really isolate the problem further or recreate it in a context without the parser-combinators library (might even have something to do with that library?).
fn parse_go_sgf(input: &str) -> Vec<Property> {
let alphabetic = |&:| {parser::satisfy(|c| {c.is_alphabetic()})};
let prop_value = |&: ident, value_type| {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(|c| c == '['),
parser::satisfy(|c| c == ']'),
value_type
)
)
};
let pmove = |&:| {
alphabetic().and(alphabetic())
.map(|a| {to_coord(a.0, a.1)})
};
let pblack = prop_value(
parser::string("B"),
pmove().map(|m| {Property::Black(m)}) //This is where I am first calling the map function.
);
let pwhite = prop_value(
parser::string("W"),
pmove().map(|m| {Property::White(m)}) //This is where the compiler complains
);
let pproperty = parser::try(pblack).or(pwhite);
let mut pnode = parser::spaces()
.with(parser::string(";"))
.with(parser::many(pproperty));
match pnode.parse(input) {
Ok((value, _)) => value,
Err(err) => {
println!("{}",err);
vec!(Property::Unkown)
}
}
}
So I am guessing this has something to do with closures all having different types. But in other cases it seems possible to call the same function with different closures. For example
let greater_than_forty_two = range(0, 100)
.find(|x| *x > 42);
let greater_than_forty_three = range(0, 100)
.find(|x| *x > 43);
Seems to work just fine.
So what is going on in my case that is different.
Also, as I am just learning, any general comments on the code are also welcome.
Unfortunately, you stumbled upon one of the rough edges in the Rust type system (which is, given the closure-heavy nature of parser-combinators, not really unexpected).
Here is a simplified example of your problem:
fn main() {
fn call_closure_fun<F: Fn(usize)>(f: F) { f(12) } // 1
fn print_int(prefix: &str, i: usize) { println!("{}: {}", prefix, i) }
let call_closure = |&: closure| call_closure_fun(closure); // 2
call_closure(|&: i| print_int("first", i)); // 3.1
call_closure(|&: i| print_int("second", i)); // 3.2
}
It gives exactly the same error as your code:
test.rs:8:18: 8:47 error: mismatched types:
expected `closure[test.rs:7:18: 7:46]`,
found `closure[test.rs:8:18: 8:47]`
(expected closure,
found a different closure) [E0308]
test.rs:8 call_closure(|&: i| print_int("second", i));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We have (referenced in the comments in the code):
a function which accepts a closure of some concrete form;
a closure which calls a function (1) with its own argument;
two invocations of closure (1), passing different closures each time.
Rust closures are unboxed. It means that for each closure the compiler generates a fresh type which implements one of closure traits (Fn, FnMut, FnOnce). These types are anonymous - they don't have a name you can write out. All you know is that these types implement a certain trait.
Rust is a strongly- and statically-typed language: the compiler must know exact type of each variable and each parameter at the compile time. Consequently it has to assign types for every parameter of every closure you write. But what type should closure argument of (2) have? Ideally, it should be some generic type, just like in (1): the closure should accept any type as long as it implements a trait. However, Rust closures can't be generic, and so there is no syntax to specify that. So Rust compiler does the most natural thing it can - it infers the type of closure argument based on the first use of call_closure, i.e. from 3.1 invocation - that is, it assigns the anonymous type of the closure in 3.1!
But this anonymous type is different from the anonymous type of the closure in 3.2: the only thing they have in common is that they both implement Fn(usize). And this is exactly what error is about.
The best solution would be to use functions instead of closures because functions can be generic. Unfortunately, you won't be able to do that either: your closures return structures which contain closures inside themselves, something like
pub struct Satisfy<I, Pred> { ... }
where Pred is later constrained to be Pred: FnMut(char) -> bool. Again, because closures have anonymous types, you can't specify them in type signatures, so you won't be able to write out the signature of such generic function.
In fact, the following does work (because I've extracted closures for parser::satisfy() calls to parameters):
fn prop_value<'r, I, P, L, R>(ident: I, value_type: P, l: L, r: R) -> pp::With<pp::With<pp::With<pp::Spaces<&'r str>, I>, pp::Spaces<&'r str>>, pp::Between<pp::Satisfy<&'r str, L>, pp::Satisfy<&'r str, R>, P>>
where I: Parser<Input=&'r str, Output=&'r str>,
P: Parser<Input=&'r str, Output=Property>,
L: Fn(char) -> bool,
R: Fn(char) -> bool {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(l),
parser::satisfy(r),
value_type
)
)
}
And you'd use it like this:
let pblack = prop_value(
parser::string("B"),
pmove().map(|&: m| Property::Black(m)),
|c| c == '[', |c| c == ']'
);
let pwhite = prop_value(
parser::string("W"),
pmove().map(|&: m| Property::White(m)),
|c| c == '[', |c| c == ']'
);
pp is introduced with use parser::parser as pp.
This does work, but it is really ugly - I had to use the compiler error output to actually determine the required return type. With the slightest change in the function it will have to be adjusted again. Ideally this is solved with unboxed abstract return types - there is a postponed RFC on them - but we're still not there yet.
As the author of parser-combinators I will just chime in on another way of solving this, without needing to use the compiler to generate the return type.
As each parser is basically just a function together with 2 associated types there are implementations for the Parser trait for all function types.
impl <I, O> Parser for fn (State<I>) -> ParseResult<O, I>
where I: Stream { ... }
pub struct FnParser<I, O, F>(F);
impl <I, O, F> Parser for FnParser<I, O, F>
where I: Stream, F: FnMut(State<I>) -> ParseResult<O, I> { ... }
These should all be replaced by a single trait and the FnParser type removed, once the orphan checking allows it. In the meantime we can use the FnParser type to create a parser from a closure.
Using these traits we can essentially hide the big parser type returned from in Vladimir Matveev's example.
fn prop_value<'r, I, P, L, R>(ident: I, value_type: P, l: L, r: R, input: State<&'r str>) -> ParseResult<Property, &'r str>
where I: Parser<Input=&'r str, Output=&'r str>,
P: Parser<Input=&'r str, Output=Property>,
L: Fn(char) -> bool,
R: Fn(char) -> bool {
parser::spaces().with(ident).with(parser::spaces()).with(
parser::between(
parser::satisfy(l),
parser::satisfy(r),
value_type
)
).parse_state(input)
}
And we can now construct the parser with this
let parser = FnParser(move |input| prop_value(ident, value_type, l, r, input));
And this is basically the best we can do at the moment using rust. Unboxed anonymous return types would make all of this significantly easier since complex return types would not be needed (nor created since the library itself could be written to utilize this, avoiding the complex types entirely).
Two facets of Rust's closures are causing your problem, one, closures cannot be generic, and two, each closure is its own type. Because closure's cannot be generic,prop_value's parameter value_type must be a specific type. Because each closure is a specific type, the closure you pass to prop_value in pwhite is a different type from the one in pblack. What the compiler does is conclude that the value_type must have the type of the closure in pblack, and when it gets to pwhite it finds a different closure, and gives an error.
Judging from your code sample, the simplest solution would probably be to make prop_value a generic fn - it doesn't look like it needs to be a closure. Alternatively, you could declare its parameter value_type to be a closure trait object, e.g. &Fn(...) -> .... Here is a simplifed example demonstrating these approaches:
fn higher_fn<F: Fn() -> bool>(f: &F) -> bool {
f()
}
let higher_closure = |&: f: &Fn() -> bool | { f() };
let closure1 = |&:| { true };
let closure2 = |&:| { false };
higher_fn(&closure1);
higher_fn(&closure2);
higher_closure(&closure1);
higher_closure(&closure2);
The existing answer(s) are good, but I wanted to share an even smaller example of the problem:
fn thing<F: FnOnce(T), T>(f: F) {}
fn main() {
let caller = |&: f| {thing(f)};
caller(|&: _| {});
caller(|&: _| {});
}
When we define caller, its signature is not fully fixed yet. When we call it the first time, type inference sets the input and output types. In this example, after the first call, caller will be required to take a closure with a specific type, the type of the first closure. This is because each and every closure has its own unique, anonymous type. When we call caller a second time, the second closure's (unique, anonymous) type doesn't fit!
As #wingedsubmariner points out, there's no way to create closures with generic types. If we had hypothetical syntax like for<F: Fn()> |f: F| { ... }, then perhaps we could work around this. The suggestion to make a generic function is a good one.

What are Some and None?

I came across some output I don't understand using Vec::get. Here's the code:
fn main() {
let command = [('G', 'H'), ('H', '5')];
for i in 0..3 {
print!(" {} ", i);
println!("{:?}", command.get(i));
}
}
the output is
0 Some(('G', 'H'))
1 Some(('H', '5'))
2 None
I've dabbled in Haskell before, and by that I mean looked at a tutorial site for 10 minutes and ran back to C++, but I remember reading something about Some and None for Haskell. I was surprised to see this here in Rust. Could someone explain why .get() returns Some or None?
The signature of get (for slices, not Vec, since you're using an array/slice) is
fn get(&self, index: usize) -> Option<&T>
That is, it returns an Option, which is an enum defined like
pub enum Option<T> {
None,
Some(T),
}
None and Some are the variants of the enum, that is, a value with type Option<T> can either be a None, or it can be a Some containing a value of type T. You can create the Option enum using the variants as well:
let foo = Some(42);
let bar = None;
This is the same as the core data Maybe a = Nothing | Just a type in Haskell; both represent an optional value, it's either there (Some/Just), or it's not (None/Nothing).
These types are often used to represent failure when there's only one possibility for why something failed, for example, .get uses Option to give type-safe bounds-checked array access: it returns None (i.e. no data) when the index is out of bounds, otherwise it returns a Some containing the requested pointer.
See also:
Why don't Option's Some and None variants need to be qualified?
What is the difference between Some and Option in Rust?
Think of Some and None as the canonical "safe" way of working around the fact that the Rust language does not support "safe" use of NULL pointers. Since the length of your Vec is 3, and you have only specified two pairs, the third pair is effectively NULL; instead of returning NULL, it returns None.
Rust provides safety guarantees by forcing us at compile-time, via Some / None, to always deal with the possibility of None being returned.
command is not a vector (type Vec<T>), it is a fixed-size array (type [(char, char); 2] in your case), and arrays are automatically borrowed into slices (views into arrays), hence you can use all methods defined on slices, including get:
Returns the element of a slice at the given index, or None if the index is out of bounds.
The behavior is pretty obvious: when given index is valid, it returns Some with the element under that index, otherwise it returns None.
There is another way to access elements in a slice - the indexing operator, which should be familiar to you:
let nums = [1, 2, 3];
let x = nums[1];
It returns the element of the slice directly, but it will fail the current task if the index is out of bounds:
fn main() {
let x = [1, 2];
for i in 0..3 {
println!("{}", x[i]);
}
}
This program fails:
% ./main2
1
2
task '<main>' failed at 'index out of bounds: the len is 2 but the index is 2', main2.rs:4
The get() method is needed for convenience; it saves you from checking in advance if the given index is valid.
If you don't know what Some and None really are and why they are needed in general, you should read the official tutorial, it explains it because it is very basic concept.
Option enum has 2 variants.
1- None is used to indicate failure or no value
2- Some which is tuple-struct that wraps the value
If you need to write this structure in OOB, for example in typescript, you would write like this. This would make it easier to visualize the situation
Define Option interface as derived class
interface Option<T = any> {
// pass all the methods here
// unwrap is used to access the wrapped value
unwrap(): T;
}
write Some class which inherits from Option
Some class returns a value
class Some<T> implements Option<T> {
private value: T;
constructor(v: T) {
this.value = v;
}
unwrap(): T {
return this.value
}}
Write None class which also inherits from Option
None class returns null
class None<T> implements Option<T> {
// you do not need constructor here
unwrap(): T {
return null as T;
}
}
The other answers discussing the return type for get() being option enum are accurate, but I think what is helpful is how to remove the some from the prints. To do that a quick way is to just call the unwrap on the option, although this is not production recommended. For a discussion on option take a look at the rust book here.
Updated with unwrap code in playground (below)
fn main() {
let command = [('G', 'H'), ('H', '5')];
for i in 0..3 {
print!(" {} ", i);
println!("{:?}", command.get(i).unwrap());
}
}

Resources