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

问题描述

我正在通过一些 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,但是迭代器引用来自 &strchars() 然后成为对不再存在的事物的引用。通过将 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);
}

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