Rust 借用检查器在 if 语句中抛出错误

Rust borrow checker throwing error in if statement

我正在 运行 通过一些 LeetCode 挑战来加深我对 Rust 的理解。我正在尝试编写以下程序,它接受 i32 输入,将其转换为 String,反转数字,然后 returns 返回 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<'_>>`, 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

这是在 playground

中重现的错误

为什么不在将 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);
}

playground


即使我们将输入作为 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);
}

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

这个 很好地解释了原因。在这个问题的上下文中:

 x.to_string().chars().rev();
//    ^         ^
//    String <- &str

to_string returns a String,但是代码在这个语句之后没有引用那个 String,所以它需要释放 String ,但是迭代器引用了 chars() 中的 &str ,然后它变成了对不再存在的东西的引用。通过将 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;
}