将元素推入 Vec 时借用时临时值下降

Temporary value dropped while borrowed while pushing elements into a Vec

我正在尝试解决 exercism 中的 RPN calculator 练习,但偶然发现了这个 temporary value dropped while borrowed 我似乎无法解决的错误。

这是我的代码:

#[derive(Debug)]
pub enum CalculatorInput {
    Add,
    Subtract,
    Multiply,
    Divide,
    Value(i32),
}

pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
    let mut stack = Vec::new();

    for input in inputs {
        match input {
            CalculatorInput::Value(value) => {
                stack.push(value);
            },
            operator => {
                if stack.len() < 2 {
                    return None;
                }
                let second = stack.pop().unwrap();
                let first = stack.pop().unwrap();
                let result = match operator {
                  CalculatorInput::Add => first + second,
                  CalculatorInput::Subtract => first - second,
                  CalculatorInput::Multiply => first * second,
                  CalculatorInput::Divide => first / second,
                  CalculatorInput::Value(_) => return None,
                };
                stack.push(&result.clone());
            }
        }
    }
    if stack.len() != 1 {
        None
    } else {
        Some(*stack.pop().unwrap())
    }
}

我得到的错误是:

error[E0716]: temporary value dropped while borrowed
  --> src/lib.rs:32:29
   |
32 |                 stack.push(&result.clone());
   |                             ^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
   |                             |
   |                             creates a temporary which is freed while still in use
...
36 |     if stack.len() != 1 {
   |        ----- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

如果我理解正确,变量 result 没有记录器存在于 for 循环之外(确实在运算符匹配分支之外),这就是我克隆它的原因,但它仍然给我同样的错误.

如何复制堆栈 Vec 所拥有的结果(如果这是我应该做的)?


仅供参考,以防万一有人觉得有用,这是考虑到所有帮助的最终解决方案:

use crate::CalculatorInput::{Add,Subtract,Multiply,Divide,Value};

#[derive(Debug)]
pub enum CalculatorInput {
    Add,
    Subtract,
    Multiply,
    Divide,
    Value(i32),
}

pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
    let mut stack: Vec<i32> = Vec::new();

    for input in inputs {
        match input {
            Value(value) => {
                stack.push(*value);
            },
            operator => {
                if stack.len() < 2 {
                    return None;
                }
                let second: i32 = stack.pop().unwrap();
                let first: i32 = stack.pop().unwrap();

                let result: i32 = match operator {
                  Add => first + second,
                  Subtract => first - second,
                  Multiply => first * second,
                  Divide => first / second,
                  Value(_) => return None,
                };
                stack.push(result);
            }
        }
    }
    if stack.len() != 1 {
        None
    } else {
        stack.pop()
    }
}

无需克隆,因为 i32 实现了 Copy 特性。

问题是我的 vec 收到的是 &i32 而不是 i32,因此 Rust 将其推断为 Vec<&i32>

你对这个简单的例子有相同的行为

fn main() {
    let mut stack = Vec::new();
    
    let a = String::from("test");
    stack.push(&a.clone());
    //-------- ^

    println!("{:?}", stack);
}

而且克隆的时候最好不要借用

fn main() {
    let mut stack = Vec::new();
    
    let a = String::from("test");
    stack.push(a.clone());
    //-------- ^
    
    println!("{:?}", stack);
}

应该像这样使用变量stack.push(result.clone());并像这样更改代码

pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
    let mut stack: Vec<i32> = Vec::new();
    //---------------- ^
    for input in inputs {
        match input {
            CalculatorInput::Value(value) => {
                stack.push(value.clone());
               //----------------- ^
            },
            operator => {
                if stack.len() < 2 {
                    return None;
                }
                let second = stack.pop().unwrap();
                let first = stack.pop().unwrap();
                let result = match operator {
                  CalculatorInput::Add => first + second,
                  CalculatorInput::Subtract => first - second,
                  CalculatorInput::Multiply => first * second,
                  CalculatorInput::Divide => first / second,
                  CalculatorInput::Value(_) => return None,
                };
                
                stack.push(result.clone());
                        //-^
            }
        }
    }
    if stack.len() != 1 {
        None
    } else {
        Some(stack.pop().unwrap())
    //------- ^
    }
}

错误是因为 Rust 没有推断出您期望的类型。

在您的代码中,value 的类型被推断为 &i32,因为 inputinputs 中元素的引用,而您 push a value 之后,因此 stack 的类型被推断为 Vec<&i32>.

最好的解决方法是明确指定堆栈的类型:

let mut stack: Vec<i32> = Vec::new();

并且因为 i32 已经实现了 Copy 特性,你永远不需要克隆一个 i32 值,如果它是一个引用,只需取消引用它。

固定码:

#[derive(Debug)]
pub enum CalculatorInput {
    Add,
    Subtract,
    Multiply,
    Divide,
    Value(i32),
}

pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
    let mut stack: Vec<i32> = Vec::new();

    for input in inputs {
        match input {
            CalculatorInput::Value(value) => {
                stack.push(*value);
            }
            operator => {
                if stack.len() < 2 {
                    return None;
                }
                let second = stack.pop().unwrap();
                let first = stack.pop().unwrap();
                let result = match operator {
                    CalculatorInput::Add => first + second,
                    CalculatorInput::Subtract => first - second,
                    CalculatorInput::Multiply => first * second,
                    CalculatorInput::Divide => first / second,
                    CalculatorInput::Value(_) => return None,
                };
                stack.push(result);
            }
        }
    }
    if stack.len() != 1 {
        None
    } else {
        Some(stack.pop().unwrap())
    }
}