GAT 是近几年才稳定的特性,解决的是「关联类型需要带参数」的问题。这篇用最典型的场景 —— 借出式迭代器 —— 验证它:没有 GAT 时标准 Iterator 为什么做不到,有了 GAT 怎么写,以及它的另一种用法(带类型参数的容器族)。
源码:
1 | struct Windows { buf: Vec<i32>, pos: usize }
2 | impl Iterator for Windows {
3 | type Item = &mut [i32];
4 | fn next(&mut self) -> Option<Self::Item> { None }
5 | }
6 | fn main() {}
编译:失败
error: associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type
--> <实验目录>/src/u44a.rs:3:17
|
3 | type Item = &mut [i32];
| ^
|
note: you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type
--> <实验目录>/src/u44a.rs:2:19
|
2 | impl Iterator for Windows {
| ^^^^^^^
error: aborting due to 1 previous error
源码:
1 | struct Windows { buf: Vec<i32>, pos: usize }
2 | impl Iterator for Windows {
3 | type Item = &'static mut [i32];
4 | fn next(&mut self) -> Option<Self::Item> {
5 | if self.pos + 2 > self.buf.len() { return None; }
6 | let w = &mut self.buf[self.pos..self.pos + 2]; self.pos += 1; Some(w)
7 | }
8 | }
9 | fn main() {}
编译:失败
error: lifetime may not live long enough
--> <实验目录>/src/u44b.rs:6:71
|
4 | fn next(&mut self) -> Option<Self::Item> {
| - let's call the lifetime of this reference `'1`
5 | if self.pos + 2 > self.buf.len() { return None; }
6 | let w = &mut self.buf[self.pos..self.pos + 2]; self.pos += 1; Some(w)
| ^^^^^^^ returning this value requires that `'1` must outlive `'static`
error: aborting due to 1 previous errorIterator 的基础见Iterator Trait;关联类型的基础见Associated Type。
源码:
1 | trait LendingIterator {
2 | type Item<'a> where Self: 'a;
3 | fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
4 | }
5 | struct WindowsMut<'s> { data: &'s mut [i32], pos: usize }
6 | impl<'s> LendingIterator for WindowsMut<'s> {
7 | type Item<'a> = &'a mut [i32] where Self: 'a;
8 | fn next<'a>(&'a mut self) -> Option<&'a mut [i32]> {
9 | if self.pos + 2 > self.data.len() { return None; }
10 | let w = &mut self.data[self.pos..self.pos + 2]; self.pos += 1; Some(w)
11 | }
12 | }
13 | fn main() {
14 | let mut v = vec![1, 2, 3, 4];
15 | let mut it = WindowsMut { data: &mut v, pos: 0 };
16 | while let Some(w) = it.next() { w[1] += w[0]; println!("窗口 {:?}", w); } // 相邻窗口重叠,每个窗口可修改
17 | println!("最终数据 {:?}", v);
18 | }
编译:成功
运行(退出码 0):
窗口 [1, 3]
窗口 [3, 6]
窗口 [6, 10]
最终数据 [1, 3, 6, 10] 源码:
1 | trait Family { type Of<T>; fn wrap<T>(t: T) -> Self::Of<T>; fn peek<T: std::fmt::Debug>(w: &Self::Of<T>) -> String; }
2 | struct VecFamily; struct OptFamily;
3 | impl Family for VecFamily { type Of<T> = Vec<T>; fn wrap<T>(t: T) -> Vec<T> { vec![t] } fn peek<T: std::fmt::Debug>(w: &Vec<T>) -> String { format!("{:?}", w) } }
4 | impl Family for OptFamily { type Of<T> = Option<T>; fn wrap<T>(t: T) -> Option<T> { Some(t) } fn peek<T: std::fmt::Debug>(w: &Option<T>) -> String { format!("{:?}", w) } }
5 | fn demo<F: Family>() -> (String, String) { (F::peek(&F::wrap(1u8)), F::peek(&F::wrap("x"))) }
6 | fn main() { println!("VecFamily:{:?}", demo::<VecFamily>()); println!("OptFamily:{:?}", demo::<OptFamily>()); }
编译:成功
运行(退出码 0):
VecFamily:("[1]", "[\"x\"]")
OptFamily:("Some(1)", "Some(\"x\")") 源码:
1 | trait Lending { type Item<'a>; fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; }
2 | fn main() {}
编译:失败
error: missing required bound on `Item`
--> <实验目录>/src/u44e.rs:1:17
|
1 | trait Lending { type Item<'a>; fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>; }
| ^^^^^^^^^^^^^-
| |
| help: add the required where clause: `where Self: 'a`
|
= note: this bound is currently required to ensure that impls have maximum flexibility
= note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
error: aborting due to 1 previous error