I have this code, but its giving me an error I don't understand:
fn main() {
// --snip--
let mut unit = String::new();
std::io::stdin()
.read_line(&mut unit)
.expect("couldn't read line!");
let unit = unit.trim().to_lowercase();
dbg!(unit);
if unit == "f" {
println!("temperature in Celsius is : {}°c", f_to_c(temp));
} else if unit == "c" {
println!("temperature in Fahrenheit is : {}°f", c_to_f(temp));
} else {
println!("'{unit}' unit not supported!");
}
}
error[E0382]: borrow of moved value: `unit`
--> src/lib.rs:16:8
|
13 | let unit = unit.trim().to_lowercase();
| ---- move occurs because `unit` has type `String`, which does not implement the `Copy` trait
14 | dbg!(unit);
| ---------- value moved here
15 |
16 | if unit == "f" {
| ^^^^ value borrowed here after move
I made unit explicitly type String but that wasn't the cause. How is this error is generated?
The dbg! macro moves it's arguments.
You can use it and not consume the argument by passing only a reference like this:
dbg!(&unit);
instead.
Related
I have the following python function that removes consecutive duplicated numbers in-place (meaning [0, 0, 1, 1, 1, 2, 2, 3] becomes [0, 1, 2, 3]):
def del_consec_dupl(nums: List[int]):
for (idx, n) in enumerate(nums):
while idx < len(nums) - 1 and n == nums[idx + 1]:
del nums[idx]
it needs to be rewritten in Rust while respecting the constraint that it must work in-place without allocating an extra vector/array. When trying to literally translating this:
fn del_consec_dupl(nums: &mut Vec<i32>) {
for (idx, n) in nums.iter().enumerate() {
while idx < nums.len() - 1 && *n == nums[idx + 1] {
nums.remove(idx);
}
}
}
will produce the following errors:
error[E0502]: cannot borrow `*nums` as immutable because it is also borrowed as mutable
--> src/main.rs:4:21
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
| ^^^^ immutable borrow occurs here
error[E0502]: cannot borrow `*nums` as immutable because it is also borrowed as mutable
--> src/main.rs:4:45
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
| ^^^^ immutable borrow occurs here
error[E0499]: cannot borrow `*nums` as mutable more than once at a time
--> src/main.rs:5:13
|
3 | for (idx, n) in nums.iter_mut().enumerate() {
| ---------------------------
| |
| first mutable borrow occurs here
| first borrow later used here
4 | while idx < nums.len() - 1 && *n == nums[idx + 1] {
5 | nums.remove(idx);
| ^^^^ second mutable borrow occurs here
error: aborting due to 3 previous errors
it seems no matter what I do, I can only solve 2 of 3. It seems the main issue here is trying to refer to the length of the vector while it is being mutated inside the iteration.
Would I need an unsafe block here? or how would you go about solving it?
I would not use remove which moves all the elements after the given index and is inefficient, but just overwrite elements in the same array, dealing with the double-borrow problem by using indexes:
fn del_consec_dupl(nums: &mut Vec<i32>) {
let mut di = 0; // "destination" increment
for si in 1..nums.len() { // increment on the "source"
if nums[si] != nums[si-1] {
di += 1;
nums[di] = nums[si];
}
}
nums.truncate(di+1); // cut off the tail
}
There's no need to use unsafe here.
Rust vectors provide the built-in dedup() method which does exactly what you are asking for, so the easiest way to write your code is nums.dedup();.
For integers, or more generally Copy types, you can also implement the same functionality using the retain() method:
fn retain_uniq<T: Copy + PartialEq>(nums: &mut Vec<T>) {
let mut previous = None;
nums.retain(|&x| Some(x) != std::mem::replace(&mut previous, Some(x)))
}
This question already has answers here:
How to lookup from and insert into a HashMap efficiently?
(2 answers)
Is there any way to return a reference to a variable created in a function?
(5 answers)
Closed 4 years ago.
I'm trying to build a HashMap with vectors as values and I have problems with borrowing / lifetimes.
The task is to find the funniest words in a given text as ranked by the funny_score method. I would like to store a list of words for each distinct score in a HashMap.
I have the following code
use std::collections::HashMap;
fn main() {
let text = "";
let mut scores: HashMap<usize, &mut Vec<&str>> = HashMap::new();
for word in text.split(' ') {
let funny_score = funny_score(word);
match scores.get_mut(&funny_score) {
Some(list) => list.push(word),
None => {
let mut list = vec![word];
scores.insert(funny_score, &mut list);
}
}
}
}
fn funny_score(_: &str) -> usize { 0 }
And the compiler says
error[E0597]: `list` does not live long enough
--> src/main.rs:12:49
|
12 | scores.insert(funny_score, &mut list);
| ^^^^ borrowed value does not live long enough
13 | }
| - `list` dropped here while still borrowed
...
16 | }
| - borrowed value needs to live until here
error[E0499]: cannot borrow `scores` as mutable more than once at a time
--> src/main.rs:12:17
|
8 | match scores.get_mut(&funny_score) {
| ------ first mutable borrow occurs here
...
12 | scores.insert(funny_score, &mut list);
| ^^^^^^ second mutable borrow occurs here
13 | }
14 | }
| - first borrow ends here
How can I make this work?
The following program tries to grade the marks of a student:
use std::io;
fn main() {
let mut in0 = String::new();
io::stdin().read_line(&mut in0).expect("stdin err");
let n: i32 = in0.trim().parse().expect("parse err");
println!("{}", n);
let mut v: Vec<i32> = Vec::new();
for _ in 0..n {
let mut inp = String::new();
io::stdin().read_line(&mut inp).expect("stdin err");
let num: i32 = inp.trim().parse().unwrap();
v.push(num);
}
let out: Vec<_> = v
.iter()
.map(|x| {
if x < 38 {
x
} else if x % 5 > 3 {
x + x % 5
} else {
x
}
})
.collect();
println!("{:?}", v);
}
While compiling, I get the following error.
error[E0308]: mismatched types
--> src/main.rs:19:20
|
19 | if x < 38 {
| ^^
| |
| expected `&i32`, found integer
| help: consider borrowing here: `&38`
error[E0308]: `if` and `else` have incompatible types
--> src/main.rs:24:17
|
21 | } else if x % 5 > 3 {
| ____________________-
22 | | x + x % 5
| | --------- expected because of this
23 | | } else {
24 | | x
| | ^ expected `i32`, found `&i32`
25 | | }
| |_____________- `if` and `else` have incompatible types
|
help: consider dereferencing the borrow
|
23 | } else *{
24 | x
25 | }
How is the x variable a &i32 type and not a i32 type?
Calling the .iter() method on a vector returns an iterator over references the vector's elements. Otherwise, it would have to move or copy the elements out of the vector, which is not desirable in the general case [1]. In the documentation this is not immediately obvious from the declaration:
pub fn iter(&self) -> Iter<T> // Return type does not look like a reference
However, the examples show that you get a reference:
assert_eq!(iterator.next(), Some(&1)); // note the `&1` instead of just `1`
The closure can be instructed to dereference the parameter:
v.iter().map(|&x| { /* do something */ })
This is fine if the vector contains Copyable types like i32. Otherwise this would result in a cannot move out of borrowed content error. In this case you will likely want to work with a reference anyway.
If you no longer need the vector after iterating you can use .into_iter(), which consumes the vector and iterates over owned items instead of references.
[1] Moving would clear the vector, which is covered by the .drain() method, and copying is not possible/efficient on all types.
If you want to consume the Vec, you must use into_iter() method:
use std::io;
fn main() {
let mut in0 = String::new();
io::stdin().read_line(&mut in0).expect("stdin err");
let n: i32 = in0.trim().parse().expect("parse err");
println!("{}", n);
let mut v: Vec<i32> = Vec::new();
for _ in 0 .. n {
let mut inp = String::new();
io::stdin().read_line(&mut inp).expect("stdin err");
let num: i32 = inp.trim().parse().unwrap();
v.push(num);
}
let out: Vec<_> = v.into_iter().map(|x| {
if x < 38 {
x
} else if x % 5 > 3 {
x + x % 5
} else {
x
}
}).collect();
println!("{:?}", out);
}
If you do not consume the vector, the things inside it can only be borrowed, not moved.
When trying to print out the contents of a multidimensional vector in Rust, it seems as though you cannot use the type Vec<Vec<str>> for the vector.
fn print_multidimensional_array(multi: &Vec<Vec<str>>) {
for y in 0..multi.len() {
for x in 0..multi[y].len() {
print!("{} ", multi[y][x]);
}
println!("");
}
}
With this code, I get the output:
error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
--> src/main.rs:1:1
|
1 | / fn print_multidimensional_array(multi: &Vec<Vec<str>>) {
2 | | for y in 0..multi.len() {
3 | | for x in 0..multi[y].len() {
4 | | print!("{} ", multi[y][x]);
... |
7 | | }
8 | | }
| |_^ `str` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `str`
= note: required by `std::vec::Vec`
What type of vector could I use for this to work?
Use Vec<Vec<&str>>.
fn print_multidimensional_array(multi: &[Vec<&str>]) {
for y in multi {
for v in y {
print!("{} ", v);
}
println!();
}
}
fn main() {
let v = vec![vec!["a", "b"], vec!["c", "d"]];
print_multidimensional_array(&v);
}
See also:
What does “`str` does not have a constant size known at compile-time” mean, and what's the simplest way to fix it?
What does "Sized is not implemented" mean?
Why is it discouraged to accept a reference to a String (&String), Vec (&Vec), or Box (&Box) as a function argument?
Passing Vec<String> as IntoIterator<&'a str>
What are the differences between Rust's `String` and `str`?
Because I like to make things overly generic...
fn print_multidimensional_array<I>(multi: I)
where
I: IntoIterator,
I::Item: IntoIterator,
<I::Item as IntoIterator>::Item: AsRef<str>,
{
for y in multi {
for v in y {
print!("{} ", v.as_ref());
}
println!();
}
}
fn main() {
let v1 = vec![vec!["a", "b"], vec!["c", "d"]];
let v2 = vec![["a", "b"], ["c", "d"]];
let v3 = [vec!["a", "b"], vec!["c", "d"]];
let v4 = [["a", "b"], ["c", "d"]];
print_multidimensional_array(&v1);
print_multidimensional_array(&v2);
print_multidimensional_array(&v3);
print_multidimensional_array(&v4);
}
Try flow link.
Here's a simple bounded polymorphism example that doesn't work the way I'd expect it to:
// #flow
function thisBreaks<T: 'a' | 'b'>(x: T): T {
if (x === 'a') {
return 'a'
} else {
return 'b'
}
}
function thisWorks<T: 'a' | 'b'>(x: T): T {
return x
}
const a = 'a'
const aPrime: 'a' = thisWorks(a)
const b = 'b'
const bPrime: 'b' = thisWorks(b)
5: return 'a'
^ string. This type is incompatible with the expected return type of
3: function thisBreaks<T: 'a' | 'b'>(x: T): T {
^ some incompatible instantiation of `T`
7: return 'b'
^ string. This type is incompatible with the expected return type of
3: function thisBreaks<T: 'a' | 'b'>(x: T): T {
^ some incompatible instantiation of `T`
I would have expected the first example to work, since e.g. the x === 'a' check could refine T to 'a', right?
This is not possible and shouldn't be possible. Here is an example that shows why:
function test<T: number | string>(x: T): T {
if (typeof x === 'number') {
return 1;
} else {
return 'b'
}
}
test((5: 5));
The function is supposed to return value of type 5, but returns 1 instead.
So, what happens? We have some unknown type T and we know that T <: string | number (T is subtype of string | number). After we refine x, we know that T is a subtype of number. It doesn't mean that T is number. It can be 5, like in the example, or 1 | 2 | 3. Knowing that T is subtype of number is not enough to create a value of T. To do that we need to know lower bound of T, but there is no way to know it.
The last question is: why is you example apparently safe then? It's simple: if T <: 'a', then it can only be 'a' (or empty, but it doesn't really matter). There are no other subtypes of 'a'. So, theoretically, Flow could support that, but its not very practical: if you know that x is 'a', than you can just return x