Luk*_*odt 9 rust generic-associated-types
最近,Rust 博客上发表了“推动 GAT 稳定化”一文。我对这个LendingIterator特性很感兴趣,但在尝试使用它时遇到了问题。这是帖子中的定义:
trait LendingIterator {
type Item<'a> where Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
Run Code Online (Sandbox Code Playgroud)
博客文章中宣传的所有内容都运行良好,我看到了 GAT 如何以多种方式提供帮助。但是:如何添加绑定到关联Item类型的特征?
使用标准Iterator特征,这很容易:
fn print_all<I>(mut i: I)
where
I: Iterator,
I::Item: std::fmt::Debug, // <-------
{
while let Some(x) = i.next() {
println!("{:?}", x);
}
}
Run Code Online (Sandbox Code Playgroud)
但是有了新特性,这个边界就不会编译(Playground):
where
I: LendingIterator,
I::Item: std::fmt::Debug,
Run Code Online (Sandbox Code Playgroud)
编译器说:
trait LendingIterator {
type Item<'a> where Self: 'a;
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
Run Code Online (Sandbox Code Playgroud)
所以我们需要一个生命周期参数。除了仅使用'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);
}
}
Run Code Online (Sandbox Code Playgroud)
(游乐场)
这无法编译:
fn print_all<I>(mut i: I)
where
I: Iterator,
I::Item: std::fmt::Debug, // <-------
{
while let Some(x) = i.next() {
println!("{:?}", x);
}
}
Run Code Online (Sandbox Code Playgroud)
这样做的原因是生命周期参数(实际上,所有通用参数)print_all是由调用者选择的。这意味着生命周期大于 的范围print_all:调用者无法知道print_all. 这意味着对 的调用必须在整个生命周期内next借用。但这包括所有的,所以我们只能借用一次!i'aprint_all
无论如何,这个解决方案是不可行的。
fn print_all<I>(mut i: I)
where
I: LendingIterator,
for<'a> I::Item<'a>: std::fmt::Debug,
Run Code Online (Sandbox Code Playgroud)
(游乐场)
嘿,它编译!然而,它有一个微妙的问题。让我们WindowsMut从博客文章中获取迭代器并尝试将其传递给print_all: Playground。它不编译:
where
I: LendingIterator,
I::Item: std::fmt::Debug,
Run Code Online (Sandbox Code Playgroud)
奇怪的!记住:
type Item<'a> where Self: 'a = &'a mut [T];
Run Code Online (Sandbox Code Playgroud)
并且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?
我明白你为什么应该扩展这种模式的原因,但这是否可能只是目前 GAT 的限制(或者只是一个错误)?不过,您可以重构您的特质,将其绑定在链的更上游,以便通过要求......
trait LendingIterator {
type Item<'a>: std::fmt::Debug where Self: 'a; // Require Debug trait
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
// Require T has Debug trait
impl<'t, T: std::fmt::Debug> LendingIterator for WindowsMut<'t, T> {
type Item<'a> where Self: 'a = &'a mut [T];
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
let retval = self.slice[self.start..].get_mut(..self.window_size)?;
self.start += 1;
Some(retval)
}
}
Run Code Online (Sandbox Code Playgroud)
并删除你对函数的限制......
fn print_all<I>(mut i: I)
where
I: LendingIterator,
// Remove
// for<'a> I::Item<'a>: std::fmt::Debug,
{
while let Some(x) = i.next() {
println!("{:?}", x);
}
}
Run Code Online (Sandbox Code Playgroud)
但是如果我取消删除特征绑定,我会得到一个与之前不同的错误......
Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `for<'a> <WindowsMut<'_, {integer}> as LendingIterator>::Item<'a> == <WindowsMut<'_, {integer}> as LendingIterator>::Item<'a>`
--> src/main.rs:45:5
|
9 | fn print_all<I>(mut i: I)
| --------- required by a bound in this
...
13 | for<'a> I::Item<'a>: std::fmt::Debug,
| --------------- required by this bound in `print_all`
...
45 | print_all(windows);
| ^^^^^^^^^ expected associated type, found `&mut [_]`
|
= note: expected associated type `<WindowsMut<'_, {integer}> as LendingIterator>::Item<'a>`
found mutable reference `&'a mut [{integer}]`
= help: consider constraining the associated type `<WindowsMut<'_, {integer}> as LendingIterator>::Item<'a>` to `&'a mut [_]` or calling a method that returns `<WindowsMut<'_, {integer}> as LendingIterator>::Item<'a>`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
For more information about this error, try `rustc --explain E0271`.
error: could not compile `playground` due to previous error
Run Code Online (Sandbox Code Playgroud)
我认为这个额外的特征界限与其他特征界限是同义反复,对我来说,这是编译器无缘无故抱怨的危险信号。
展示示例作品的Playground 。