平衡括号时的生命周期问题

时间:2018-08-15 18:44:15

标签: rust borrowing

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

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结构上添加了生命周期,但没有成功。一种猜测是可以通过在各处使用拥有的String来解决,但这似乎不必要,而且我真的很想看到解决方案。

1 个答案:

答案 0 :(得分:4)

您似乎将字符串文字"("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)。

关于后续问题

  

假设我们有一个包含字符串切片的堆栈,那么如何处理生命周期问题

好吧,这将完全取决于为什么需要保存字符串(我们认为没有必要)。

由于问题来自尝试存储对临时字符串的引用(代码中的c.to_string()),因此您可以存储拥有的String(而是已经分配了它们)。