Generic
我们已经用 Option 和 Box 触及了一些泛型。不过,到目前为止,我们已经设法避免了对任意元素声明任何实际上是泛型的新类型。
事实证明这真的很简单。现在让我们将所有类型设为泛型类型:
pub struct List<T> {
head: Link<T>,
}
type Link<T> = Option<Box<Node<T>>>;
struct Node<T> {
elem: T,
next: Link<T>,
}
你只是把所有的东西都变得更尖锐一点,然后你的代码就突然变得通用了。当然,我们不能这样做,否则编译器会非常疯狂。
> 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> 。
但是我们在所有这些 impls 中使用的是什么?就像List一样,我们希望我们的实现能够与所有T一起使用。 因此,就像List一样,让我们的展示点很明确:
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();
}
}
}
就是这样!
> 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很容易,我想对那些甚至没有改变的新事物说一句特别的话:
pub fn new() -> Self {
List { head: None }
}
沐浴在自我的荣耀中,重构和复制粘贴编码的守护者。同样有趣的是,当我们构造一个 List 的实例时,我们不会写 List<T> 。这个部分是基于我们从一个函数返回它,该函数需要一个 List<T> 来推断的。
好吧,让我们继续全新的行为!
Last updated
Was this helpful?