Reputation: 1293
I'm running through some LeetCode challenges to build up my understanding of Rust. I'm trying to write the following program that takes an i32
input, converts it to a String
, reverses the digits, and returns back an i32
number.
In the case of negative numbers, e.g. -132
, when the number is reversed the hyphen has to be popped off the stack: -132
-> 231-
-> 231
.
I've written the following code but I'm bumping up against the borrow checker, can anyone help?
impl Solution {
pub fn reverse(x: i32) -> i32 {
if(x == 0){
return x;
}
let reversed : std::iter::Rev<std::str::Chars> = x.to_string().chars().rev();
if reversed.last().unwrap() == '-' { //error occurs here
return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
} else {
return reversed.collect::<String>().parse::<i32>().unwrap();
}
}
}
Line 6, Char 61: temporary value dropped while borrowed (solution.rs)
|
6 | let reversed : &std::iter::Rev<std::str::Chars> = &x.to_string().chars().rev();
| ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
7 | if reversed.last().unwrap() == '-' {
| -------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
Line 7, Char 12: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
7 | if reversed.last().unwrap() == '-' {
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 8, Char 20: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
8 | return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 8, Char 52: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
8 | return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 10, Char 20: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
10 | return reversed.collect::<String>().parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Here's the error reproduced in a playground
Upvotes: 0
Views: 204
Reputation: 3169
Original error reproduced in this playground
Here's a solution that is close to your approach that fixes the error:
fn reverse(x: i32) -> i32 {
if x == 0 {
return x;
}
let mut reversed:String = x.to_string().chars().rev().collect::<String>();
if reversed.chars().last() == Some('-') {
reversed.pop();
}
reversed.parse::<i32>().unwrap()
}
working version: playground
This other post has good explanation of why. In the context of this question:
x.to_string().chars().rev();
// ^ ^
// String <- &str
to_string
returns a String
, but the code has no reference to that String
after this statement, so it needs to free the String
, but the iterator refers to the &str
from chars()
which then becomes a reference to something that no longer exists. By changing the type of reversed
to String
and using collect
then Rust can bind the new data to the local variable and doesn't have to drop it at the end of the statement.
Upvotes: 3
Reputation: 23463
Does the LeetCode challenge impose the int→string→int conversions? I would do it directly on ints:
fn reverse (x: i32) -> i32 {
let mut x = x.abs();
let mut y = 0;
while x != 0 {
y = y*10 + x%10;
x = x/10;
}
return y;
}
Upvotes: 2
Reputation: 15165
Why not just take the absolute value of x
before converting it to a String
so you don't have to deal with the hyphen edge case?
fn reverse(x: i32) -> i32 {
x.abs()
.to_string()
.chars()
.rev()
.collect::<String>()
.parse::<i32>()
.unwrap()
}
fn main() {
assert_eq!(reverse(1234567), 7654321);
assert_eq!(reverse(-1234567), 7654321);
}
Even if we get the input as a String
and have to deal with the hyphen the most idiomatic solution would be to filter()
it out:
fn reverse(x: String) -> i32 {
x.chars()
.filter(|&c| c != '-')
.rev()
.collect::<String>()
.parse::<i32>()
.unwrap()
}
fn main() {
assert_eq!(reverse(1234567.to_string()), 7654321);
assert_eq!(reverse((-1234567).to_string()), 7654321);
}
Upvotes: 1