【问题标题】:Breadth first search and lifetimes广度优先搜索和生命周期
【发布时间】:2016-11-03 03:21:35
【问题描述】:

我想写一个函数,在二叉树上使用广度优先搜索来按顺序打印节点值:

use std::collections::VecDeque;
use std::ops::Deref;

struct BinarySearchNode<'a> {
    value: &'a str,
    key: i32,
    left: Option<Box<BinarySearchNode<'a>>>,
    right: Option<Box<BinarySearchNode<'a>>>,
}

impl<'a> BinarySearchNode<'a> {
    pub fn print(&self) -> String {
        let mut queue = VecDeque::new();
        let mut output = String::new();
        queue.push_back(&self);

        while let Some(ref current) = queue.pop_front() {
            if let Some(left_node) = current.left {
                queue.push_back(&left_node.deref());
            }
            if let Some(right_node) = current.right {
                queue.push_back(&right_node.deref());
            }

            output = output + current.value + "\n";
        }

        output
    }
}

fn main() {}

我得到了错误

error: borrowed value does not live long enough
  --> src/main.rs:19:34
   |
19 |                 queue.push_back(&left_node.deref());
   |                                  ^^^^^^^^^^^^^^^^^ does not live long enough
   |
note: reference must be valid for the block suffix following statement 0 at 13:40...
  --> src/main.rs:13:41
   |
13 |         let mut queue = VecDeque::new();
   |                                         ^
note: ...but borrowed value is only valid for the statement at 19:16
  --> src/main.rs:19:17
   |
19 |                 queue.push_back(&left_node.deref());
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
  --> src/main.rs:19:17
   |
19 |                 queue.push_back(&left_node.deref());
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: `left_node` does not live long enough
  --> src/main.rs:19:34
   |
19 |                 queue.push_back(&left_node.deref());
   |                                  ^^^^^^^^^
   |
note: reference must be valid for the block suffix following statement 0 at 13:40...
  --> src/main.rs:13:41
   |
13 |         let mut queue = VecDeque::new();
   |                                         ^
note: ...but borrowed value is only valid for the if let at 18:12
  --> src/main.rs:18:13
   |
18 |             if let Some(left_node) = current.left {
   |             ^

error: borrowed value does not live long enough
  --> src/main.rs:22:34
   |
22 |                 queue.push_back(&right_node.deref());
   |                                  ^^^^^^^^^^^^^^^^^^ does not live long enough
   |
note: reference must be valid for the block suffix following statement 0 at 13:40...
  --> src/main.rs:13:41
   |
13 |         let mut queue = VecDeque::new();
   |                                         ^
note: ...but borrowed value is only valid for the statement at 22:16
  --> src/main.rs:22:17
   |
22 |                 queue.push_back(&right_node.deref());
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
  --> src/main.rs:22:17
   |
22 |                 queue.push_back(&right_node.deref());
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: `right_node` does not live long enough
  --> src/main.rs:22:34
   |
22 |                 queue.push_back(&right_node.deref());
   |                                  ^^^^^^^^^^
   |
note: reference must be valid for the block suffix following statement 0 at 13:40...
  --> src/main.rs:13:41
   |
13 |         let mut queue = VecDeque::new();
   |                                         ^
note: ...but borrowed value is only valid for the if let at 21:12
  --> src/main.rs:21:13
   |
21 |             if let Some(right_node) = current.right {
   |             ^

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:18:38
   |
18 |             if let Some(left_node) = current.left {
   |                         ---------    ^^^^^^^ cannot move out of borrowed content
   |                         |
   |                         hint: to prevent move, use `ref left_node` or `ref mut left_node`

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:21:39
   |
21 |             if let Some(right_node) = current.right {
   |                         ----------    ^^^^^^^ cannot move out of borrowed content
   |                         |
   |                         hint: to prevent move, use `ref right_node` or `ref mut right_node`

我需要deref(),因为仅仅使用运算符* 会导致类型不匹配,因为它期望的是引用而不是框。似乎那些取消引用略有不同,至少在稳定时我也不能解构它。

我知道这个值是在while 循环中的范围内,并且没有足够长的时间在VecDeque 中(如果这是适合该工作的数据结构),但我不确定是什么延长生命周期的最佳方法是,或者是否有更好的方法来编写整个事情,因为它感觉有点复杂。

我的主要问题是我不确定从哪里开始重构这段代码,而且令人惊讶的是,我很难找到在 Rust 中对二叉树执行广度优先搜索以从中获取模式的示例。

【问题讨论】:

    标签: algorithm rust


    【解决方案1】:

    您的主要问题在于这一行(以及right 版本):

    if let Some(left_node) = current.left
    

    这会尝试将current.left 中包含的值移动到右侧的模式中。问题是current.leftOption&lt;Box&lt;BinarySearchNode&lt;'a&gt;&gt;&gt;。当您将Box 移出current 时,这将使current 没有left 的有效值!将来访问该值会导致不良行为。

    相反,您需要将值保留在原处,而是获取参考。两种主要方式是使用ref 模式修饰符:

    if let Some(ref left_node) = current.left
    

    或致电as_ref:

    if let Some(left_node) = current.left.as_ref()
    

    这里是完整的代码:

    use std::collections::VecDeque;
    
    struct BinarySearchNode<'a> {
        value: &'a str,
        key: i32,
        left: Option<Box<BinarySearchNode<'a>>>,
        right: Option<Box<BinarySearchNode<'a>>>,
    }
    
    impl<'a> BinarySearchNode<'a> {
        pub fn print(&self) -> String {
            let mut queue = VecDeque::new();
            let mut output = String::new();
            queue.push_back(self);
    
            while let Some(current) = queue.pop_front() {
                if let Some(left_node) = current.left.as_ref() {
                    queue.push_back(left_node);
                }
                if let Some(right_node) = current.right.as_ref() {
                    queue.push_back(right_node);
                }
    
                output = output + current.value + "\n";
            }
    
            output
        }
    }
    
    fn main() {
        let root = BinarySearchNode {
            value: "a",
            key: 0,
            left: Some(Box::new(BinarySearchNode {
                value: "b",
                key: 1,
                left: None,
                right: None,
            })),
            right: Some(Box::new(BinarySearchNode {
                value: "c",
                key: 2,
                left: None,
                right: None,
            })),
        };
        println!("{}", root.print());
    }
    

    【讨论】:

    • 嗯,这并不明显,但现在对我来说很有意义。我认为我的参考生活不够长。谢谢你的解释。
    【解决方案2】:

    试试这个:

    pub fn print(&self) -> String {
        let mut queue = VecDeque::new();
        let mut output = String::new();
    
        if let Some(ref left_node) = self.left {
            queue.push_back(left_node);
        }
        if let Some(ref right_node) = self.right {
            queue.push_back(right_node);
        }
    
        while let Some(ref current) = queue.pop_front() {
            if let Some(ref left_node) = current.left {
                queue.push_back(left_node);
            }
            if let Some(ref right_node) = current.right {
                queue.push_back(right_node);
            }
    
            output = output + current.value + "\n";
        }
    
        output
    }
    

    【讨论】:

    • 您的答案会更有用一些文本突出并解释此代码和 OP 之间的差异。否则人们会发现很难将您所做的更改应用到遇到相同问题的他们自己的代码中。
    • 这段代码也没有打印出起始节点的值(self);它只打印出孩子。
    猜你喜欢
    • 2011-01-31
    • 2016-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-02
    • 1970-01-01
    相关资源
    最近更新 更多