如何添加绑定到泛型关联类型的特征?
最近,Rust 博客上发表了“推动 GAT 稳定化”一文。我对这个LendingIterator特性很感兴趣,但在尝试使用它时遇到了问题。这是帖子中的定义:
trait LendingIterator {
type Item<'a> where Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
trait LendingIterator {
type Item<'a> where Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
博客文章中宣传的所有内容都运行良好,我看到了 GAT 如何以多种方式提供帮助。但是:如何添加绑定到关联Item类型的特征?
使用标准Iterator特征,这很容易:
fn print_all<I>(mut i: I)
where
I: Iterator,
I::Item: std::fmt::Debug, // <--
where
I: LendingIterator,
I::Item: std::fmt::Debug,
where
I: LendingIterator,
I::Item: std::fmt::Debug,
-----
{
while let Some(x) = i.next() {
println!("{:?}", x);
}
}
但是有了新特性,这个边界就不会编译(Playground):
编译器说:
所以我们需要一个生命周期参数。除了仅使用'static(过于严格)之外,我还看到了两种方法来实现这一点。然而,两者都有微妙但显着的缺点/问题。
函数的生命周期参数
fn print_all<'a, I>(mut i: I)
where
I: 'a + LendingIterator,
I::Item<'a>: std::fmt::Debug,
{
while let Some(x) = i.next() {
println!("{:?}", x);
}
}
(游乐场)
这无法编译:
fn print_all<I>(mut i: I)
where
I: Iterator,
I::Item: std::fmt::Debug, // <-------
{
while let Some(x) = i.next() {
println!("{:?}", x);
}
}
这样做的原因是生命周期参数(实际上,所有通用参数)print_all是由调用者选择的。这意味着生命周期大于 的范围print_all:调用者无法知道print_all. 这意味着对 的调用必须在整个生命周期内next借用。但这包括所有的,所以我们只能借用一次!i'aprint_all
无论如何,这个解决方案是不可行的。
更高种类的特征边界(?y bois)
fn print_all<I>(mut i: I)
where
I: LendingIterator,
for<'a> I::Item<'a>: std::fmt::Debug,
(游乐场)
嘿,它编译!然而,它有一个微妙的问题。让我们WindowsMut从博客文章中获取迭代器并尝试将其传递给print_all: Playground。它不编译:
奇怪的!记住:
type Item<'a> where Self: 'a = &'a mut [T];
并且std::fmt::Debug绝对是针对切片的可变引用实现的。不管一生。(比较文档)。
我认为界限不满足,因为for<'a>意味着“对于所有可能的生命周期”,其中包括'static. 让我们写出来:
是否对所有可能的sWindowsMut<'t, T>::Item<'a>实施?是否实现?那是。该类型仅在. 还有这个奇怪的界限。并且绝对不满意,除非。Debug'aWindowsMut<'t, T>::Item<'static>Debug&'static mut [T]T: 'staticwhere Self: 'aWindowsMut<'t, T>: 'static't == 'static
我如何正确地添加一个绑定到Item类型LendingIterator和实现print_all?这应该是可能的吧?这个问题已经讨论过了吗?我上面的推理是否不正确,尤其是关于 HRTB?