【Rust每周一知】一種奇怪的表示 T::Item
- 2020 年 3 月 16 日
- 筆記
我們都知道,Rust有一種叫 完全限定語法(fully-qualified syntax) 的東西。請看下面的例子:
trait AAA { type Item; fn test(); } struct Foo; impl AAA for Foo { type Item = String; fn test() { println!("a test."); } } fn main() { let f: Foo::Item= String::from("test foo"); println!("{}", f); }
編譯,會提示如下錯誤:
error[E0223]: ambiguous associated type --> src/main1.rs:20:12 | 20 | let f: Foo::Item= String::from("test foo"); | ^^^^^^^^^ help: use fully-qualified syntax: `<Foo as Trait>::Item`
應該寫成:
let f: <Foo as AAA>::Item= String::from("test foo");
就可以編譯通過了,這就是所謂:完全限定語法。
但是,在閱讀一些工程的程式碼的時候,可以發現一種不尋常的用法。我設計了一個例子如下:
trait AAA { type Item0; fn test(); } impl<T> AAA for T { type Item0 = String; fn test() { println!("test it"); } } trait BBB { type Item1; fn doit(&self); } struct Foo<T> { foo: T } impl<T> BBB for Foo<T> where T: AAA { type Item1 = T::Item0; fn doit(&self) { println!("just do it."); } } fn main() { let f = Foo::<u8>{ foo: 100 }; f.doit(); }
上面例子中,T::Item0
這個寫法,有點超出我們的認知。泛型可以直接引用其 Trait bound 的 associated type 嗎?好像是的。本例子能編譯通過並順利運行。
再來看一個稍微複雜一點的例子:
struct Doubler<I> { iter: I, } impl<I> Iterator for Doubler<I> where I: Iterator, I::Item: std::ops::Add<Output=I::Item> + Copy, { type Item = I::Item; fn next(&mut self) -> Option<Self::Item> { match self.iter.next() { None => None, Some(x) => Some(x + x), } } } fn sum(range: u32) -> u32 { (1..=range).fold(0, |sum, i| sum + i) } fn sum2<I>(iter: I) -> I::Item where I: Iterator, I::Item: std::ops::Add<Output=I::Item> + From<u8>, { iter.fold(From::from(0u8), std::ops::Add::add) } fn main() { for i in (Doubler{iter: 1..11u32}) { print!("{} ", i); } println!(); println!("Sum is {}", (1..11).fold(0, |sum, i| sum + i)); println!("Sum is {} using sum helper", sum(10)); println!("Sum is {} using sum good helper", sum2(0..11)); println!("ALL DONE"); }
上例中的 I::Item
也是這種情況。
其實也並不難理解,只是在第一次遇到的時候,會很奇怪,Rust 怎麼會有這種語法。於是設計了例子來驗證這個問題。原來還真是可以的。
本文所有示例地址: https://github.com/daogangtang/learn-rust/tree/master/04generic_with_associated_type