平衡支架时的寿命问题

Lifetime issues while balancing brackets

我面临生命周期的问题。实现应该平衡三种括号:([{。我正在为此使用堆栈,但 运行 遇到了一些问题。

pub struct Brackets {
    stack: Vec<char>,
}

impl<'a> From<&'a str> for Brackets {
    fn from(input: &str) -> Self {
        let mut stack: Vec<char> = Vec::new();
        for c in input.chars() {
            stack.push(c);
        }

        Brackets { stack }
    }
}

impl<'a> Brackets {
    pub fn are_balanced(&self) -> bool {
        let mut stack = Vec::new();
        for c in &self.stack {
            // Converts the character to a String to a &str... Feels dumb
            let slice = &c.to_string()[..];
            match slice {
                "(" | "[" | "{" => stack.push(slice),
                ")" | "]" | "}" => {
                    let popped = stack.pop();
                    match popped {
                        Some(")") => {
                            if slice != "(" {
                                return false;
                            };
                        }
                        Some("]") => {
                            if slice != "[" {
                                return false;
                            };
                        }
                        Some("}") => {
                            if slice != "{" {
                                return false;
                            };
                        }
                        _ => return false,
                    }
                }
                _ => continue,
            }
        }

        true
    }
}

我想压入左括号,弹出右括号。如果右括号与左括号不匹配,则括号不平衡。我忽略任何非括号输入。

我遇到的问题:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:21:26
   |
21 |             let slice = &c.to_string()[..];
   |                          ^^^^^^^^^^^^^ temporary value does not live long enough
...
47 |         }
   |         - temporary value dropped here while still borrowed
...
50 |     }
   |     - temporary value needs to live until here

我知道 are_balanced(&self) 函数中的堆栈比我压入堆栈的 slice 变量的寿命更长。我该如何解决这个问题?我尝试将堆栈的类型更改为 &'a str 并在 Brackets 结构上设置生命周期但没有成功。一个猜测是它可以通过在任何地方使用拥有的 Strings 来解决,但它似乎不必要地昂贵,我真的很想看到解决这个问题的方法..

您似乎混淆了字符串文字 "("char 文字 '('。如果您替换所有字符串文字,您的代码有效:

for &c in &self.stack {
    match c {
        '(' | '[' | '{' => stack.push(c),
        ')' | ']' | '}' => {
            let popped = stack.pop();
            match popped {
                Some(')') => {
                    if c != '(' {
                        return false;
                    };
                }
                Some(']') => {
                    if c != '[' {
                        return false;
                    };
                }
                Some('}') => {
                    if c != '{' {
                        return false;
                    };
                }
                _ => return false,
            }
        }
        _ => continue,
    }
}

Rust 与 Python 或 Bash 不同,char 和字符串具有不同的类型。虽然它有点误导,因为它并不真正代表一个字符,而是一个 Unicode 标量值。有些你会认为是字符的东西实际上不能用 char 表示(例如,很多表情符号,或一些重音字母,如 ɔ̃)。这意味着您可能要三思而后行,是对某些应用程序使用 char 还是字符串。然而,为了平衡括号,使用 char 是完全没问题的;我不希望花哨的 Unicode 括号没有自己的标量值。

请注意,我也已将循环更改为使用 &c,这是因为迭代堆栈会产生对其元素的引用(因此在我们的示例中为 &char),但这有点不方便在这种情况下。使用 &c 确保 c 本身是一个 char (&c: &char <=> c: char).

至于后续问题

say we have a stack with string slices, how can one deal with the lifetime issues

嗯,这完全取决于为什么需要保存字符串(我们已经看到没有必要)。

由于尝试存储对临时字符串的引用(代码中的 c.to_string()),因此您可以存储拥有的 String(无论如何您已经分配了它们) ).