新增章节: 还 OK 的单向链表 - IterMut

pull/563/head
sunface 3 years ago
parent b54092ab8c
commit 3b6cdae19d

@ -162,8 +162,8 @@
- [还可以的单向链表](too-many-lists/ok-stack/intro.md) - [还可以的单向链表](too-many-lists/ok-stack/intro.md)
- [优化类型定义](too-many-lists/ok-stack/type-optimizing.md) - [优化类型定义](too-many-lists/ok-stack/type-optimizing.md)
- [定义 Peek 函数](too-many-lists/ok-stack/peek.md) - [定义 Peek 函数](too-many-lists/ok-stack/peek.md)
- [IntoIter 和 Iter](too-many-lists/iter.md) - [IntoIter 和 Iter](too-many-lists/ok-stack/iter.md)
- [IterMut以及完整代码](too-many-lists/ok-stack/itermut.md)
- [易混淆概念解析](confonding/intro.md) - [易混淆概念解析](confonding/intro.md)
- [切片和切片引用](confonding/slice.md) - [切片和切片引用](confonding/slice.md)
- [Eq 和 PartialEq](confonding/eq.md) - [Eq 和 PartialEq](confonding/eq.md)

@ -262,7 +262,7 @@ Rust 有一个叫做 `Copy` 的特征,可以用在类似整型这样在栈中
- 所有浮点数类型,比如 `f64` - 所有浮点数类型,比如 `f64`
- 字符类型,`char`。 - 字符类型,`char`。
- 元组,当且仅当其包含的类型也都是 `Copy` 的时候。比如,`(i32, i32)` 是 `Copy` 的,但 `(i32, String)` 就不是。 - 元组,当且仅当其包含的类型也都是 `Copy` 的时候。比如,`(i32, i32)` 是 `Copy` 的,但 `(i32, String)` 就不是。
- 引用类型,例如[转移所有权](#转移所有权)中的最后一个例子 - 不可变引用 `&T` ,例如[转移所有权](#转移所有权)中的最后一个例子**但是注意: 可变引用 `&mut T` 是不可以 Copy的**
## 函数传值与返回 ## 函数传值与返回

@ -0,0 +1,326 @@
# IterMut以及完整代码
上一章节中我们讲到了要为 `List` 实现三种类型的迭代器并实现了其中两种: `IntoIter``Iter`。下面再来看看最后一种 `IterMut`
再来回顾下 `Iter` 的实现:
```rust
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> { /* stuff */ }
}
```
这段代码可以进行下脱糖( desugar ):
```rust
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next<'b>(&'b mut self) -> Option<&'a T> { /* stuff */ }
}
```
可以看出 `next` 方法的输入和输出之间的生命周期并没有关联,这样我们就可以无条件的一遍又一遍地调用 `next`:
```rust
let mut list = List::new();
list.push(1); list.push(2); list.push(3);
let mut iter = list.iter();
let x = iter.next().unwrap();
let y = iter.next().unwrap();
let z = iter.next().unwrap();
```
对于不可变借用而言,这种方式没有任何问题,因为不可变借用可以同时存在多个,但是如果是可变引用呢?因此,大家可能会以为使用安全代码来写 `IterMut` 是一件相当困难的事。但是令人诧异的是,事实上,我们可以使用安全的代码来为很多数据结构实现 `IterMut`
先将之前的代码修改成可变的:
```rust
pub struct IterMut<'a, T> {
next: Option<&'a mut Node<T>>,
}
impl<T> List<T> {
pub fn iter_mut(&self) -> IterMut<'_, T> {
IterMut { next: self.head.as_deref_mut() }
}
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
self.next.map(|node| {
self.next = node.next.as_deref_mut();
&mut node.elem
})
}
}
```
```shell
> cargo build
error[E0596]: cannot borrow `self.head` as mutable, as it is behind a `&` reference
--> src/second.rs:95:25
|
94 | pub fn iter_mut(&self) -> IterMut<'_, T> {
| ----- help: consider changing this to be a mutable reference: `&mut self`
95 | IterMut { next: self.head.as_deref_mut() }
| ^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
error[E0507]: cannot move out of borrowed content
--> src/second.rs:103:9
|
103 | self.next.map(|node| {
| ^^^^^^^^^ cannot move out of borrowed content
```
果不其然,两个错误发生了。第一错误看上去很清晰,甚至告诉了我们该如何解决:
```rust
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut { next: self.head.as_deref_mut() }
}
```
但是另一个好像就没那么容易了。但是之前的代码就可以工作啊,为何这里就不行了?
原因在于有些类型可以 [Copy](https://course.rs/basic/ownership/ownership.html#拷贝浅拷贝),有些不行。而`Option` 和不可变引用 `&T` 恰恰是可以 Copy 的,但尴尬的是,可变引用 `&mut T` 不可以,因此这里报错了。
因此我们需要使用 `take` 方法来处理这种情况:
```rust
fn next(&mut self) -> Option<Self::Item> {
self.next.take().map(|node| {
self.next = node.next.as_deref_mut();
&mut node.elem
})
}
```
```shell
> cargo build
```
老规矩,来测试下:
```rust
#[test]
fn iter_mut() {
let mut list = List::new();
list.push(1); list.push(2); list.push(3);
let mut iter = list.iter_mut();
assert_eq!(iter.next(), Some(&mut 3));
assert_eq!(iter.next(), Some(&mut 2));
assert_eq!(iter.next(), Some(&mut 1));
}
```
```shell
> cargo test
Running target/debug/lists-5c71138492ad4b4a
running 6 tests
test first::test::basics ... ok
test second::test::basics ... ok
test second::test::iter_mut ... ok
test second::test::into_iter ... ok
test second::test::iter ... ok
test second::test::peek ... ok
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured
```
最终,我们完成了迭代器的功能,下面是完整的代码。
## 完整代码
```rust
pub struct List<T> {
head: Link<T>,
}
type Link<T> = Option<Box<Node<T>>>;
struct Node<T> {
elem: T,
next: Link<T>,
}
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
})
}
pub fn peek(&self) -> Option<&T> {
self.head.as_ref().map(|node| {
&node.elem
})
}
pub fn peek_mut(&mut self) -> Option<&mut T> {
self.head.as_mut().map(|node| {
&mut node.elem
})
}
pub fn into_iter(self) -> IntoIter<T> {
IntoIter(self)
}
pub fn iter(&self) -> Iter<'_, T> {
Iter { next: self.head.as_deref() }
}
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut { next: self.head.as_deref_mut() }
}
}
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();
}
}
}
pub struct IntoIter<T>(List<T>);
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
// access fields of a tuple struct numerically
self.0.pop()
}
}
pub struct Iter<'a, T> {
next: Option<&'a Node<T>>,
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.next.map(|node| {
self.next = node.next.as_deref();
&node.elem
})
}
}
pub struct IterMut<'a, T> {
next: Option<&'a mut Node<T>>,
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next(&mut self) -> Option<Self::Item> {
self.next.take().map(|node| {
self.next = node.next.as_deref_mut();
&mut node.elem
})
}
}
#[cfg(test)]
mod test {
use super::List;
#[test]
fn basics() {
let mut list = List::new();
// Check empty list behaves right
assert_eq!(list.pop(), None);
// Populate list
list.push(1);
list.push(2);
list.push(3);
// Check normal removal
assert_eq!(list.pop(), Some(3));
assert_eq!(list.pop(), Some(2));
// Push some more just to make sure nothing's corrupted
list.push(4);
list.push(5);
// Check normal removal
assert_eq!(list.pop(), Some(5));
assert_eq!(list.pop(), Some(4));
// Check exhaustion
assert_eq!(list.pop(), Some(1));
assert_eq!(list.pop(), None);
}
#[test]
fn peek() {
let mut list = List::new();
assert_eq!(list.peek(), None);
assert_eq!(list.peek_mut(), None);
list.push(1); list.push(2); list.push(3);
assert_eq!(list.peek(), Some(&3));
assert_eq!(list.peek_mut(), Some(&mut 3));
list.peek_mut().map(|value| {
*value = 42
});
assert_eq!(list.peek(), Some(&42));
assert_eq!(list.pop(), Some(42));
}
#[test]
fn into_iter() {
let mut list = List::new();
list.push(1); list.push(2); list.push(3);
let mut iter = list.into_iter();
assert_eq!(iter.next(), Some(3));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), None);
}
#[test]
fn iter() {
let mut list = List::new();
list.push(1); list.push(2); list.push(3);
let mut iter = list.iter();
assert_eq!(iter.next(), Some(&3));
assert_eq!(iter.next(), Some(&2));
assert_eq!(iter.next(), Some(&1));
}
#[test]
fn iter_mut() {
let mut list = List::new();
list.push(1); list.push(2); list.push(3);
let mut iter = list.iter_mut();
assert_eq!(iter.next(), Some(&mut 3));
assert_eq!(iter.next(), Some(&mut 2));
assert_eq!(iter.next(), Some(&mut 1));
}
}
```

@ -3,6 +3,7 @@
## 2022-03-13 ## 2022-03-13
- 新增章节: [还 OK 的单向链表 - IterMut](https://course.rs/too-many-lists/ok-stack/itermut.html)
- 新增章节: [还 OK 的单向链表 - IntoIter 和 Iter](https://course.rs/too-many-lists/iter.html) - 新增章节: [还 OK 的单向链表 - IntoIter 和 Iter](https://course.rs/too-many-lists/iter.html)
- 优化[进一步深入特赠 - 关联类型](https://course.rs/basic/trait/advance-trait.html#关联类型)中的部分内容,感谢 AllenYu0018 的[提示](https://github.com/sunface/rust-course/discussions/392). - 优化[进一步深入特赠 - 关联类型](https://course.rs/basic/trait/advance-trait.html#关联类型)中的部分内容,感谢 AllenYu0018 的[提示](https://github.com/sunface/rust-course/discussions/392).

Loading…
Cancel
Save