Get first element from HashMap - hashmap

I have a HashMap and need to get the first element:
type VarIdx = std::collections::HashMap<u16, u8>;
fn get_first_elem(idx: VarIdx) -> u16 {
let it = idx.iter();
let ret = match it.next() {
Some(x) => x,
None => -1,
};
ret
}
fn main() {}
but the code doesn't compile:
error[E0308]: match arms have incompatible types
--> src/main.rs:5:15
|
5 | let ret = match it.next() {
| _______________^
6 | | Some(x) => x,
7 | | None => -1,
8 | | };
| |_____^ expected tuple, found integral variable
|
= note: expected type `(&u16, &u8)`
found type `{integer}`
note: match arm with an incompatible type
--> src/main.rs:7:17
|
7 | None => -1,
| ^^
how can I fix it?

There is no such thing as the "first" item in a HashMap. There are no guarantees about the order in which the values are stored nor the order in which you will iterate over them.
If order is important then perhaps you can switch to a BTreeMap, which preserves order based on the keys.
If you just need to get the first value that you come across, in other words any value, you can do something similar to your original code: create an iterator, just taking the first value:
fn get_first_elem(idx: VarIdx) -> i16 {
match idx.values().next() {
Some(&x) => x as i16,
None => -1,
}
}
The method values() creates an iterator over just the values. The reason for your error is that iter() will create an iterator over pairs of keys and values which is why you got the error "expected tuple".
To make it compile, I had to change a couple of other things: -1 is not a valid u16 value so that had to become i16, and your values are u8 so had to be cast to i16.
As another general commentary, returning -1 to indicate failure is not very "Rusty". This is what Option is for and, given that next() already returns an Option, this is very easy to accomplish:
fn get_first_elem(idx: VarIdx) -> Option<u8> {
idx.values().copied().next()
}
The .copied() is needed in order to convert the &u8 values of the iterator into u8.

HashMap::iter returns an iterator over (&Key, &Value) pairs. What you want is HashMap::values, which produces an iterator that only produces the values of the HashMap.
Note that the order of the values is random. It has nothing to do with the order you put the values in or with the actual value of the values.

Related

How to get many references to one object, using SlotMap?

enum List<'a> {
Cons(isize, &'a List<'a>),
Nil,
}
fn main() {
use List::*;
use slotmap::SlotMap;
let mut table = SlotMap::new();
let nil = table.insert(Nil);
table.insert(Cons(1, table[nil]));
}
SlotMap<K: Key, V>'s insert is
pub fn insert(&mut self, value: V) -> K
and its impl<K: Key, V> Index<K> is
fn index(&self, key: K) -> &V
So surely since I insert List into table, table[key] should return &List right?
Why am I getting this error:
error[E0308]: mismatched types
--> src/main.rs:11:26
|
11 | table.insert(Cons(1, table[nil]));
| ---- ^^^^^^^^^^
| | |
| | expected `&List<'_>`, found enum `List`
| | help: consider borrowing here: `&table[nil]`
| arguments to this enum variant are incorrect
|
How should I actually be using SlotMap to get many (immutable) references to SlotMap-owned objects?
Yes, index() returns a &V, but the operator [] works such that a[b] is equivalent to *a.index(b).
Which is handy, because when you write for example an array:
let mut a = [1,2,3];
a[0] = 0;
you don't want to write *a[0] = 0;! And consider arrays of arrays... *(*m[0])[1] = 0;, that wouldn't be pretty.
So if you want the reference to the value just reborrow (that is what the compiler suggests):
table.insert(Cons(1, &table[nil]));
Or alternatively call index manually:
table.insert(Cons(1, table.index(nil)));
But that begs the question, if you are adding all your lists and partial lists to the slotmap, why not:
enum List {
Cons(isize, Key),
Nil,
}
And get rid of lifetime issues forever?

Error with non matching type: Option<&[u8]> and Option<&[u8;32]>

I playing with the Rust code, and I've got to a place in which I have a problem with converting Option<&[u8; 32]> to Option<&[u8]>.
A (very) simplified example:
pub type Foo = [u8; 32];
fn fun_one(inp: Option<&[u8]>) {
println!("{:?}", inp);
}
fn fun_two(x: Option<&Foo>) {
fun_one(x)
}
fn main() {
let x = [11u8; 32];
fun_two(Some(&x));
}
Link: Rust Playground
error[E0308]: mismatched types
--> src/main.rs:8:13
|
8 | fun_one(x)
| ^ expected slice `[u8]`, found array `[u8; 32]`
|
= note: expected enum `Option<&[u8]>`
found enum `Option<&[u8; 32]>`
A slice isn't just a pointer over an array. It's both the pointer to the data and a length (see Arrays and Slices) as it refers to only a part of the array. This is why the types aren't compatible.
What you want here is a slice over the whole array, which you get with the .. full range expression: slice = &array[..].
Having an option, you can conditionnaly apply this transformation using map.
Combining all this:
fn fun_two(x: Option<&Foo>) {
fun_one(x.map(|a| &a[..]))
}

Rust book listing 10-16: expected type `T` found type `&T`

I am stuck at Listing 10-16 when I try to implement the following modification:
If we change the return type to be &T instead of T and change the body
of the function to return a reference, we wouldn’t need either the
Clone or Copy trait bounds and we wouldn’t be doing any heap
allocations. Try implementing these alternate solutions on your own!
My code is
use std::cmp::PartialOrd;
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest: &T = &list[0];
for &item in list.iter() {
if item > largest {
largest = &item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("The largest number is {}", result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("The largest char is {}", result);
}
I get the error
error[E0308]: mismatched types
--> src/main.rs:7:19
|
7 | if item > largest {
| ^^^^^^^ expected type parameter, found &T
|
= note: expected type `T`
found type `&T`
list.iter() gives you an iterator over references to elements of list.
Using the for &item in ... syntax, notably the &item pattern, you dereference it and use it as a T. It might be counter-intuitive at first, but &item in this case does the opposite of what &item would do in most other contexts (e.g. when passing to a function).
However, largest is explicitly defined as a &T, so in this case the < operator tries to compare two different types: T and &T
Remove the & from the pattern and it all works out.
for item in list.iter() {
if item > largest {
largest = item;
}
}

Why do I get the error "expected integral variable, found Option" when matching on an integer?

I am trying to use match in Rust. I wrote a function:
fn main() {
let try = 3;
let x = match try {
Some(number) => number,
None => 0,
};
}
But I'm getting the error:
error[E0308]: mismatched types
--> src/main.rs:4:9
|
4 | Some(number) => number,
| ^^^^^^^^^^^^ expected integral variable, found enum `std::option::Option`
|
= note: expected type `{integer}`
found type `std::option::Option<_>`
error[E0308]: mismatched types
--> src/main.rs:5:9
|
5 | None => 0,
| ^^^^ expected integral variable, found enum `std::option::Option`
|
= note: expected type `{integer}`
found type `std::option::Option<_>`
I tried something like let try: i32 = 3; to make sure that try is an integral value, but I still get the same error.
I think you want this:
fn main() {
let try = Some(3);
let x = match try {
Some(number) => number,
None => 0,
};
}
The issue is that you're trying to match an integer against Some(...) and None, which are Options. This doesn't really make sense... an integer can never be None.
Instead, I think you want to use the type Option<i32> and convert it to an i32 by using a default value. The above code should accomplish that. Note that if that's all you're trying to do, this is an easier way:
let x = try.unwrap_or(0);
In match expressions the type of the value you are matching on must correspond to the variants in the block following it; in your case this means that try either needs to be an Option or the match block needs to have integral variants.
I highly recommend reading The Rust Book; Rust is strongly typed and this is one of the most basic concepts you will need to familiarize yourself with.

How do I find the index of an element in an array, vector or slice?

I need to find an index of an element in a vector of strings. This is what I got so far:
fn main() {
let test: Vec<String> = vec![
"one".to_string(),
"two".to_string(),
"three".to_string(),
"four".to_string(),
];
let index: i32 = test
.iter()
.enumerate()
.find(|&r| r.1.to_string() == "two".to_string())
.unwrap()
.0;
}
It produces an error:
error[E0308]: mismatched types
--> src/main.rs:9:22
|
9 | let index: i32 = test
| ______________________^
10 | | .iter()
11 | | .enumerate()
12 | | .find(|&r| r.1.to_string() == "two".to_string())
13 | | .unwrap()
14 | | .0;
| |__________^ expected i32, found usize
I assume that's because enumerate() returns a tuple of (usize, _) (correct me if I'm wrong), but how do I convert usize to i32 here? If there is a better approach, I'm open to suggestions.
I think you should look at the position method instead.
fn main() {
let test = vec!["one", "two", "three"];
let index = test.iter().position(|&r| r == "two").unwrap();
println!("{}", index);
}
You can test it here.
Note that this works for any iterator, so it can be used for vectors, arrays, and slices, all of which produce iterators.
TLDR Use an iterator with the position method, the Rust docs shows a good example.
No, it's because indices are usize, not i32. In fact, i32 is completely inappropriate for this purpose; it may not be large enough, and there's no reason for it to be signed. Just use usize.
Some other notes: calling to_string() is not free, and you don't need it for the comparison; you can compare string slices just fine!
Also, if you really want to turn a usize into an i32, you can do that with a cast: x as i32, though this will not produce an error on over- or under-flow (i.e. the result may be negative).
All that said, as noted in Mathieu David's answer, there's a position method on iterators that does what you want.

Resources