在没有生命周期参数

时间:2017-01-03 16:40:55

标签: rust lifetime

我正在尝试在Rust中实现BST(适用于Rust中{3}}可爱介绍中的HW3),我遇到了生命周期中的错误,以及如何限制与类型相关的类型的生命周期没有一生。

#[derive(Debug)]
pub struct BST<T>
    where T: Ord
{
    root: Option<Box<Node<T>>>,
}

// A couple dozen lines of BST stuff

impl<'a, T> IntoIterator for BST<T>
    where T: Ord
{
    type Item = T;
    type IntoIter = BSTIter<'a, T>; // <- my intuition is that I should
                                        // be able to say "BSTIter lives as
                                        // long as BST."

    fn into_iter(&'a mut self) -> BSTIter<'a, T> {
        BSTIter::new(&mut self)
    }
}


pub struct BSTIter<'a, T: 'a>
    where T: Ord + 'a
{
    bst: &'a mut BST<T>,
    node_list: Vec<&'a Node<T>>, // this is where the need for a lifetime on
                                 // BSTIter comes from
}


impl<'a, T> BSTIter<'a, T>
    where T: Ord
{
    fn new(&mut bst: BST<T>) -> BSTIter<'a, T> {
        let traverse_stack = Vec::new();
        if let Some(ref x) = bst.root {
            traverse_stack.push(x);
        }
        BSTIter {
            bst: bst,
            node_list: traverse_stack,
        }
    }
}


impl<'a, T> Iterator for BSTIter<'a, T>
    where T: Ord
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        // BST iteration details
    }
}

就目前而言,此代码会吐出错误

error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
   --> src/lib.rs:117:7
    |
117 | impl<'a, T> IntoIterator for BST <T> where T: Ord {
    |      ^^ unconstrained lifetime parameter

如果IntoIterator特征不要求我指定type IntoIterator = BSTIter,则实施块可能只有into_iter方法签名into_iter<'a>(&'a mut self) -> BSTIter<'a, T>。由于我需要指定BSTIter的生命周期,似乎我需要为整个BST类型指定生命周期。再一次,我的直觉说我不应该在BST上指定一个生命周期来为它创建一个迭代器。

我意识到这两个解决方案可能是

中的一个(或两个)
  1. 有一种语言功能可以帮助我解决这个问题
  2. 在此过程中,我的代码变得非常惯用Rust
  3. 如果我可以获得有关如何使上述代码段工作的帮助,或者我应该如何处理这些生命周期和所有权详细信息,那将非常感谢!

1 个答案:

答案 0 :(得分:3)

您误解了IntoIterator的目的和用法。它将值转换为迭代器; 消耗过程中的值。但是,您的迭代器正在尝试返回对集合的引用。 You cannot return references into the iterator,因此使用树,将所有权转移到迭代器是没有意义的。

您称之为BSTIter而不是BSTIntoIter这一事实表明了承诺;因为它是返回引用的迭代器的惯用名。

您希望为IntoIterator实施&'a BST<T>,而不是BST<T>。你可以 BST<T>实现它,但是你想要产生T,而不是&T

在修复之后,出现了很多编译错误:整个代码中的类型不匹配,特征中的方法签名不正确(fn into_iter(self)只允许你),出于某种原因,有&#39; sa对树的可变引用,变量应该是可变的......

#[derive(Debug)]
struct Node<T>(Option<Box<T>>);

#[derive(Debug)]
pub struct BST<T>
    where T: Ord
{
    root: Option<Box<Node<T>>>,
}

impl<'a, T> IntoIterator for &'a BST<T>
    where T: Ord
{
    type Item = T;
    type IntoIter = BSTIter<'a, T>;
    fn into_iter(self) -> BSTIter<'a, T> {
        BSTIter::new(self)
    }
}

pub struct BSTIter<'a, T: 'a>
    where T: Ord + 'a
{
    bst: &'a BST<T>,
    node_list: Vec<&'a Node<T>>,
}

impl<'a, T> BSTIter<'a, T>
    where T: Ord
{
    fn new(bst: &'a BST<T>) -> BSTIter<'a, T> {
        let mut traverse_stack = Vec::new();
        if let Some(ref x) = bst.root {
            traverse_stack.push(&**x);
        }
        BSTIter {
            bst: bst,
            node_list: traverse_stack,
        }
    }
}

impl<'a, T> Iterator for BSTIter<'a, T>
    where T: Ord
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        None
    }
}

fn main() {}