问题描述
我正在通过一些 LeetCode 挑战来建立我对 Rust 的理解。我正在尝试编写以下程序,该程序接受 i32
输入,将其转换为 String
,反转数字,然后返回一个 i32
数字。
在负数的情况下,例如-132
,当数字反转时,连字符必须从堆栈中弹出:-132
-> 231-
-> 231
。
我已经编写了以下代码,但我遇到了借用检查器,有人可以帮忙吗?
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<'_>>`,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
这是在 playground 中重现的错误
解决方法
在此playground中复制的原始错误
这是一个与您修复错误的方法接近的解决方案:
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()
}
工作版本:playground
这个 other post 很好地解释了原因。在这个问题的上下文中:
x.to_string().chars().rev();
// ^ ^
// String <- &str
to_string
返回一个String
,但是代码在这条语句之后没有引用那个String
,所以需要释放String
,但是迭代器引用来自 &str
的 chars()
然后成为对不再存在的事物的引用。通过将 reversed
的类型更改为 String
并使用 collect
,Rust 可以将新数据绑定到局部变量,而不必在语句的末尾删除它。
LeetCode 挑战是否强加了 int→string→int 转换?我会直接在整数上做:
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;
}
,
为什么不在将 x
转换为 String
之前直接取其绝对值,这样您就不必处理连字符边缘情况?
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);
}
即使我们将输入作为 String
获取并且必须处理连字符,最惯用的解决方案是将其 filter()
输出:
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);
}