在迭代器特征中指定关联类型的生存期

时间:2019-12-29 10:32:09

标签: rust

我是Rust的新手,我试图找出在Rust中执行以下操作的最佳方法是什么:

struct ThingIterator {
    current: String,
    stop: String,
}

impl Iterator for ThingIterator {
    type Item = &str;
    fn next(&mut self) -> Option<&str> {
        if self.current == self.stop {
            return None;
        }
        // For testing
        self.current = self.stop;
        Some(&self.current)
    }
}

fn main() {
    let pi = ThingIterator {
        current: String::from("Ask"),
        stop: String::from("Zoo"),
    };
    println!("Number of things={}", pi.count());
}

我的错误是:

error[E0106]: missing lifetime specifier
 --> src/main.rs:7:17
  |
7 |     type Item = &str;
  |                 ^ expected lifetime parameter

error: aborting due to previous error

这很有意义,我需要指定next()返回的引用有效的时间。我猜测该函数本身很好,因为可以延长生命周期(不确定消除的共轭)-但我需要某种方式定义“类型Item =&str”行的生命周期。

在我的情况下,只要“当前”有效,即与“自我”的有效期相同,该有效期就有效。

在Rust书籍或其他文档中没有发现任何可以帮助我弄清这种情况的东西。

P.S。抱歉,如果我要屠宰术语,那么我对Rust还是很陌生。 谢谢

2 个答案:

答案 0 :(得分:3)

您还不能。这将需要generic associated types (GATs)。到今天为止,它仍然只是RFC。

当前的Iterator / Stream API有时被称为“分离”:

  

这个想法是由Item返回的Streamself是“分离的”,这意味着它可以独立于self进行存储和移动。

假设,GAT登陆后,人们将可以编写如下内容:

trait AttachedStream {
    type Item<'s> where Self: 's;
    //       note the `'s` here!

    fn poll_next<'s>(
        self: Pin<&'s mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Self::Item<'s>>>;
    //                         ^^^^
    // `'s` is the lifetime of the `self` reference.
    // Thus, the `Item` that gets returned may
    // borrow from `self`.
}

这正是您想要的。查看Niko's async interview #2了解更多有趣的细节。

答案 1 :(得分:2)

在定义类型&mut self时,nextItem上的生存期不在范围内,因此Item不能依赖于该生存期。相反,通常有ThingIterator持有引用而不是拥有的数据。如果仍然有一个拥有数据的结构,则可能会为IntoIterator实现&OwnsData转换为使用引用的类型。

// ThingIterator is now generic in the lifetime 'a
// and it holds references rather than owned Strings.
struct ThingIterator<'a> {
    current: &'a str,
    stop: &'a str,
}

impl<'a> Iterator for ThingIterator<'a> {
    // Now we can use the lifetime from ThingIterator here.
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        if self.current == self.stop {
            return None;
        }
        // For testing
        self.current = self.stop;
        Some(self.current)
    }
}

// Typically, you'll have a type that owns its data
// Like Vec<T>, HashSet<T>, etc.
struct OwnsData {
    current: String,
    stop: String,
}

impl OwnsData {
    // We'll have the traditional method that takes a reference
    // to self and returns an iterator over references into self.

    // Explicit lifetimes aren't needed, but it might help with understanding.
    // fn iter<'a>(&'a self) -> ThingIterator<'a> {

    fn iter(&self) -> ThingIterator {
        ThingIterator {
            current: &self.current,
            stop: &self.stop,
        }
    }
}

// Then, we'll implement IntoIterator for references to OwnsData
// using the OwnsData::iter method defined above.
// This is helpful because for loops and many iterator methods
// use IntoIterator to work.
impl<'a> IntoIterator for &'a OwnsData {
    // We'll be converting into ThingIterator
    type IntoIter = ThingIterator<'a>;
    type Item = &'a str;

    fn into_iter(self) -> ThingIterator<'a> {
        self.iter()
    }
}

fn main() {
    let pi = ThingIterator {
        current: "Ask",
        stop: "Zoo",
    };
    println!("Number of things={}", pi.count());

    // Alternatively, we could start with Strings
    // and use OwnsData
    let tau = OwnsData {
        current: "Ask".to_string(),
        stop: "Zoo".to_string(),
    };
    println!("Number of things={}", tau.iter().count());
}

(playground)

另请参见

P.S。您要查找的单词是“已消除”。

相关问题