2.2 泛型
原文链接: https://rust-unofficial.github.io/too-many-lists/second-generic.html
我们已经接触过 Option 和 Box 里的泛型。但到目前为止,我们还没声明过真正对任意元素泛型的新类型。
其实非常简单。现在就把所有类型都改成泛型:
1
2
3
4
5
6
7
8
9
10
| pub struct List<T> {
head: Link<T>,
}
type Link<T> = Option<Box<Node<T>>>;
struct Node<T> {
elem: T,
next: Link<T>,
}
|
只要给所有东西加上尖括号,代码就泛型化了。当然,不能只这么做,否则编译器会大发雷霆。
1
2
3
4
5
6
7
8
9
10
11
12
13
| > cargo test
error[E0107]: wrong number of type arguments: expected 1, found 0
--> src/second.rs:14:6
|
14 | impl List {
| ^^^^ expected 1 type argument
error[E0107]: wrong number of type arguments: expected 1, found 0
--> src/second.rs:36:15
|
36 | impl Drop for List {
| ^^^^ expected 1 type argument
|
问题很清楚:我们在谈论 List,但它已经不再是原来的那个了。和 Option、Box 一样,现在必须始终说 List<Something>。
那这些 impl 里的 Something 是什么?和 List 一样,我们希望实现适用于所有 T。所以,和 List 一样,让 impl 也带上尖括号:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| impl<T> List<T> {
pub fn new() -> Self {
List { head: None }
}
pub fn push(&mut self, elem: T) {
let new_node = Box::new(Node {
elem: elem,
next: self.head.take(),
});
self.head = Some(new_node);
}
pub fn pop(&mut self) -> Option<T> {
self.head.take().map(|node| {
self.head = node.next;
node.elem
})
}
}
impl<T> Drop for List<T> {
fn drop(&mut self) {
let mut cur_link = self.head.take();
while let Some(mut boxed_node) = cur_link {
cur_link = boxed_node.next.take();
}
}
}
|
……就这样!
1
2
3
4
5
6
7
8
9
| > cargo test
Running target/debug/lists-5c71138492ad4b4a
running 2 tests
test first::test::basics ... ok
test second::test::basics ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
|
所有代码现在都对任意 T 完全泛型。天哪,Rust 真简单。特别要提一下 new,它甚至都没变:
1
2
3
| pub fn new() -> Self {
List { head: None }
}
|
沐浴在 Self 的荣光里吧——重构与复制粘贴的守护者。另外,构造 List 实例时我们也不写 List<T>,编译器会根据从期望 List<T> 的函数返回这一事实推断出来。
好,接下来是完全新的行为!