我們都知道,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