How to match against Some(&T)? [duplicate] - rust

This question already has answers here:
What is the difference between `e1` and `&e2` when used as the for-loop variable?
(1 answer)
Why is `ref` used instead of an asterisk in pattern matching?
(2 answers)
Closed 2 years ago.
The following code won't compile:
#[derive(Debug)]
struct Foo {
x: i32,
}
pub fn main() {
let a = vec![Foo { x: 1 }, Foo { x: 2 }];
match a.get(0) {
Some(&x) => println!("ref {:?}", x),
None => {}
}
}
Throws this error:
error[E0507]: cannot move out of a shared reference
--> src/main.rs:8:11
|
8 | match a.get(0) {
| ^^^^^^^^
9 | Some(&x) => println!("ref {:?}", x),
| -
| |
| data moved here
| move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
I thought std::Vec<T>::get returns Some(&T) on success. Doesn't that mean an ampersand should be used in pattern matching?

I thought std::Vec<T>::get returns Some(&T) on success
Yes, you get an Option over a reference. Said otherwise, x, in Some(x) is a reference over the Foo instance.
But you do want a reference: the only way to print the element without removing it from the vector is to pass a reference to println, not the element itself. That's why
Some(x) => println!("ref {:?}", x),
is the right way.
When you do
Some(&x) => println!("ref {:?}", x),
on the other way, as &x is the reference over the Foo instance, x is the Foo instance, and thus you'd be moving it out of the vector when matching, which you can't do with a shared reference you got with get (and something you certainly don't want to do anyway).

Related

Why is rust raising error '`()` is not an iterator'? [duplicate]

This question already has an answer here:
How do I sort an array?
(1 answer)
Closed 6 days ago.
I tried to write a program that does the following thing: take all suffixes of a given string s, then sort these suffixes with dictionary order.
here is my code:
let mut sorted = (0..s.len())
.map(|i| (i, &s[i..s.len()]))
.collect::<Vec<(usize, &str)>>()
.sort_by_key(|k| k.1);
for elem in sorted {
println!("{} {}", elem.0, elem.1);
}
and rust compiler gives an error:
error[E0277]: `()` is not an iterator
--> src/lt05.rs:7:17
|
7 | for elem in sorted {
| ^^^^^^ `()` is not an iterator
|
= help: the trait `Iterator` is not implemented for `()`
= note: required for `()` to implement `IntoIterator`
Could anyone please explain what is wrong in this code?
Vec::sort_by_key sorts a vector in place and returns (). So in your code sorted ends up being assigned (), the unit type which you can't iterate over.
To fix this you can simply sort the vector after you've constructed it by moving the call to sort_by_key into a separate statement and then iterate over the sorted vector. See example below. Here is a Rust Playground which does this.
fn main() {
let s = "thisisatest";
let mut sorted =
(0..s.len())
.map(|i| (i, &s[i..s.len()]))
.collect::<Vec<(usize, &str)>>();
sorted.sort_by_key(|k| k.1);
for elem in sorted {
println!("{} {}", elem.0, elem.1);
}
}
Output
6 atest
8 est
1 hisisatest
4 isatest
2 isisatest
5 satest
3 sisatest
9 st
10 t
7 test
0 thisisatest

What is the correct way to get values via a method without moving it? [duplicate]

This question already has answers here:
How to prevent a value from being moved?
(2 answers)
When would an implementation want to take ownership of self in Rust?
(2 answers)
What do I have to do to solve a "use of moved value" error?
(3 answers)
How can I solve "use of moved value" and "which does not implement the `Copy` trait"?
(1 answer)
Closed 3 years ago.
I don't understand why Rust moves the value. Do I oversee a major point in the ownership?
The struct MyData is a smaller version. I store some values in this struct, and want to access the stored values, but the compiler tells me after the second access, that the value was moved.
I want to make some getters for my structs. I already derived Clone, but that does not help.
The problem occurs on Windows 10 with the GNU-Compiler and on Kubuntu 18.04 LTS.
My current workaround is to clone the data beforehand, but this can't be the correct way.
#[derive(Debug, Clone)]
struct MyData {
val1: i32,
val2: String,
}
impl MyData {
pub fn get_val1(self) -> i32 {
return self.val1.clone();
}
pub fn get_val2(self) -> String {
return self.val2.clone();
}
pub fn get_both(self) -> (i32, String) {
return (self.val1, self.val2);
}
}
fn main() {
let d = MyData {
val1: 35,
val2: String::from("Hello World"),
};
let both = d.get_both();
let x = d.get_val1();
let y = d.get_val2();
}
error[E0382]: use of moved value: `d`
--> src/main.rs:28:13
|
27 | let both = d.get_both();
| - value moved here
28 | let x = d.get_val1();
| ^ value used here after move
|
= note: move occurs because `d` has type `MyData`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `d`
--> src/main.rs:29:13
|
28 | let x = d.get_val1();
| - value moved here
29 | let y = d.get_val2();
| ^ value used here after move
|
= note: move occurs because `d` has type `MyData`, which does not implement the `Copy` trait
I expect that let x = d.get_val1(); won't cause an error. In my understanding of ownership in Rust, I did not move the value, since I'm calling a method of MyData and want to work with the value.
Why does Rust move the value and to whom?

What allows the implicit conversion from a struct to its reference when calling a method? [duplicate]

This question already has answers here:
What are Rust's exact auto-dereferencing rules?
(4 answers)
Closed 4 years ago.
Which rule makes the following code work?
struct Dummy(i32);
impl Dummy {
pub fn borrow(&self) {
println!("{}", self.0);
}
}
fn main() {
let d = Dummy(1);
(&d).borrow();
d.borrow();
}
I expect d.borrow() won't work as it passes in self which doesn't match the method signature borrow(&self).
From the reference :
A method call consists of an expression (the receiver) followed by a
single dot, an expression path segment, and a parenthesized
expression-list
When looking up a method call, the receiver may be automatically
dereferenced or borrowed in order to call a method.
Note:
Automatic dereference or borrow is only valid for the receiver. If there is no expression as receiver it will not work. Compiler will expect the borrowed type.
Example:
fn main() {
let d = Dummy(1);
let borrowed = Dummy::borrow(d);
}
Compiler will show an error:
error[E0308]: mismatched types
--> src/main.rs:12:34
|
12 | let borrowed = Dummy::borrow(d);
| ^
| |
| expected &Dummy, found struct `Dummy`
| help: consider borrowing here: `&d`
|
= note: expected type `&Dummy`
found type `Dummy`

Cannot move out of borrowed context [duplicate]

This question already has an answer here:
Cannot move out of borrowed content / cannot move out of behind a shared reference
(1 answer)
Closed 4 years ago.
I have a very simple piece of code that I cannot get to compile:
struct X;
struct A {
field: Option<Box<X>>,
}
impl A {
pub fn get_field(&self) -> Option<&X> {
return self.field.map(|value| &*value);
}
}
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:9:16
|
9 | return self.field.map(|value| &*value);
| ^^^^ cannot move out of borrowed content
error[E0597]: `*value` does not live long enough
--> src/lib.rs:9:40
|
9 | return self.field.map(|value| &*value);
| ^^^^^-
| | |
| | borrowed value only lives until here
| borrowed value does not live long enough
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 8:5...
--> src/lib.rs:8:5
|
8 | / pub fn get_field(&self) -> Option<&X> {
9 | | return self.field.map(|value| &*value);
10| | }
| |_____^
I don't really understand why this doesn't work.
I don't really understand why this doesn't work.
Your code defined a struct A that may or may not hold a X in the heap (not in the stack).
In the method get_field you were given a reference to the struct, but you want to get a reference to the inner X, if possible.
The above are concluded only by looking at the function signatures and struct definition of A.
Looking into the function body, self.field is of type Option<_>, and map is its method. Look at the documentation for Option::map:
pub fn map<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> U,
Maps an Option<T> to Option<U> by applying a function to a contained value.
It accepts a closure that can only run once, accepts a Box<X> in your case, then according to your function return type it should return &X. It looks like a perfect match at first glance since if value: Box<X> then *value: X and &*value: &X, but it does not compile! What's wrong?
If you look more carefully at the signature of map you see it has 2 parameters, not one. The first parameter is the "method receiver" self and its type is Self.
In Rust, this means this call will need to consume the method receiver; the object you used to call the method would be no longer valid after this call.
However, your get_field method is not allowed to remove the method receiver self.field: self is only a reference to A, so self.field is also just a reference . You then cannot call map to consume self.field.
The solution, is to use as_ref:
pub fn as_ref(&self) -> Option<&T>
Converts from Option<T> to Option<&T>.
Although it says converts from Option<T>, but from the signature you can see it accepts &Option<T>, so it just moves the outside & inside. Now you can use map.
pub fn get_field(&self) -> Option<&X> {
return self.field.as_ref().map(|value| &*value);
}
Now it works.

Get first element from 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.

Resources