关联类型和泛型参数都能让 trait「带一个类型」,但它们的语义不同:关联类型是「这个类型实现 trait 时确定的一个类型」。这篇用编译器的报错把两者的区别摆出来,再看约束里的几种写法和标准库里最常见的三个关联类型。
源码:
1 | trait Container {
2 | type Item;
3 | fn first(&self) -> Option<&Self::Item>;
4 | fn size(&self) -> usize;
5 | }
6 | struct Words(Vec<String>);
7 | struct Nums([i32; 3]);
8 | impl Container for Words { type Item = String; fn first(&self) -> Option<&String> { self.0.first() } fn size(&self) -> usize { self.0.len() } }
9 | impl Container for Nums { type Item = i32; fn first(&self) -> Option<&i32> { self.0.first() } fn size(&self) -> usize { 3 } }
10 | fn show<C: Container>(c: &C) -> String where C::Item: std::fmt::Debug { format!("size={} first={:?}", c.size(), c.first()) }
11 | fn main() {
12 | println!("{}", show(&Words(vec!["a".into(), "b".into()])));
13 | println!("{}", show(&Nums([7, 8, 9])));
14 | }
编译:成功
运行(退出码 0):
size=2 first=Some("a")
size=3 first=Some(7) 源码:
1 | trait From2<T> { fn conv(&self) -> T; }
2 | struct N(i32);
3 | impl From2<i64> for N { fn conv(&self) -> i64 { self.0 as i64 } }
4 | impl From2<String> for N { fn conv(&self) -> String { self.0.to_string() } }
5 | fn main() {
6 | let n = N(5);
7 | let a: i64 = n.conv();
8 | let b: String = n.conv();
9 | println!("{a} {b}");
10 | }
编译:成功
运行(退出码 0):
5 5
编译:失败
error[E0283]: type annotations needed
--> <实验目录>/src/u43c.rs:5:31
|
5 | fn main() { let n = N(5); let x = n.conv(); }
| ^ ---- type must be known at this point
|
note: multiple `impl`s satisfying `N: From2<_>` found
--> <实验目录>/src/u43c.rs:3:1
|
3 | impl From2<i64> for N { fn conv(&self) -> i64 { self.0 as i64 } }
| ^^^^^^^^^^^^^^^^^^^^^
4 | impl From2<String> for N { fn conv(&self) -> String { self.0.to_string() } }
| ^^^^^^^^^^^^^^^^^^^^^^^^
help: consider giving `x` an explicit type
|
5 | fn main() { let n = N(5); let x: /* Type */ = n.conv(); }
| ++++++++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0283`.
源码:
1 | trait Container { type Item; fn get(&self) -> Self::Item; }
2 | struct N(i32);
3 | impl Container for N { type Item = i64; fn get(&self) -> i64 { self.0 as i64 } }
4 | impl Container for N { type Item = String; fn get(&self) -> String { self.0.to_string() } }
5 | fn main() {}
编译:失败
error[E0119]: conflicting implementations of trait `Container` for type `N`
--> <实验目录>/src/u43d.rs:4:1
|
3 | impl Container for N { type Item = i64; fn get(&self) -> i64 { self.0 as i64 } }
| -------------------- first implementation here
4 | impl Container for N { type Item = String; fn get(&self) -> String { self.0.to_string() } }
| ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `N`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`. 源码:
1 | use std::fmt::Debug;
2 | use std::ops::Add;
3 | fn sum_all<I: Iterator<Item = u32>>(it: I) -> u32 { it.sum() }
4 | fn debug_all<I>(it: I) -> Vec<String> where I: Iterator, I::Item: Debug { it.map(|x| format!("{:?}", x)).collect() }
5 | fn add_twice<T: Add<Output = T> + Copy>(a: T) -> T { a + a }
6 | fn output_name<T: Add>(_: T) -> &'static str { std::any::type_name::<<T as Add>::Output>() }
7 | fn main() {
8 | println!("{}", sum_all(vec![1u32, 2, 3].into_iter()));
9 | println!("{:?}", debug_all("a b".split(' ')));
10 | println!("{} {}", add_twice(2), add_twice(1.5));
11 | println!("i32 + i32 的 Output 类型:{}", output_name(1i32));
12 | }
编译:成功
运行(退出码 0):
6
["\"a\"", "\"b\""]
4 3
i32 + i32 的 Output 类型:i32
编译:失败
error[E0277]: cannot add a float to an integer
--> <实验目录>/src/u43f.rs:1:23
|
1 | fn main() { let x = 1 + 2.0; }
| ^ no implementation for `{integer} + {float}`
|
= help: the trait `Add<{float}>` is not implemented for `{integer}`
= help: the following other types implement trait `Add<Rhs>`:
`&f128` implements `Add<f128>`
`&f128` implements `Add`
`&f16` implements `Add<f16>`
`&f16` implements `Add`
`&f32` implements `Add<f32>`
`&f32` implements `Add`
`&f64` implements `Add<f64>`
`&f64` implements `Add`
and 56 others
…(共 21 行) 源码:
1 | use std::any::type_name;
2 | use std::ops::{Add, Deref};
3 | fn item_of<I: Iterator>(_: &I) -> &'static str { type_name::<I::Item>() }
4 | fn target_of<D: Deref>(_: &D) -> &'static str { type_name::<D::Target>() }
5 | fn output_of<A: Add<B>, B>(_: &A, _: &B) -> &'static str { type_name::<A::Output>() }
6 | fn main() {
7 | println!("vec::IntoIter<u8>::Item = {}", item_of(&vec![1u8].into_iter()));
8 | println!("Box<String>::Target = {}", target_of(&Box::new(String::new())));
9 | println!("String::Target = {}", target_of(&String::new()));
10 | println!("String + &str 的 Output = {}", output_of(&String::new(), &"x"));
11 | }
编译:成功
运行(退出码 0):
vec::IntoIter<u8>::Item = u8
Box<String>::Target = alloc::string::String
String::Target = str
String + &str 的 Output = alloc::string::String更高一层的泛型关联类型(GAT)见Generic Associated Type;迭代器的 Item 见Iterator Trait。