Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 29 additions & 15 deletions src/too-many-lists/unsafe-queue/layout2.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ struct Node<T> {
}
```

细心的同学可能会发现,此时 `Link<T>` 和 `tail` 的类型 `*mut Node<T>` 一致了。我们可以把 `tail` 的类型也改为 `Link<T>` ,让代码更一致。

```rust
pub struct List<T> {
head: LinkT>,
// tail: *mut Node<T>,
tail: Link<T>, // 新老好人卡此时一致了
}
```


请大家牢记:当使用裸指针时,`Option` 对我们是相当不友好的,所以这里不再使用。在后面还将引入 `NonNull` 类型,但是现在还无需操心。

## 基本操作
Expand Down Expand Up @@ -89,31 +100,31 @@ struct Node<T> {
> 将裸指针转换成 `Box` 以实现自动的清理:
>
> ```rust
>
> let x = Box::new(String::from("Hello"));
> let ptr = Box::into_raw(x);
> let x = unsafe { Box::from_raw(ptr) };

太棒了,简直为我们量身定制。而且它还很符合我们试图遵循的规则: 从安全的东东开始,将其转换成裸指针,最后再将裸指针转回安全的东东以实现安全的 drop。

现在,我们就可以到处使用裸指针,也无需再注意 unsafe 的范围,反正现在都是 unsafe 了,无所谓。
现在,我们就可以到处使用裸指针,只不过要注意 unsafe 的范围要尽可能小。大家可以再看下[之前的章节](https://course.rs/advance/unsafe/intro.html#控制-unsafe-的使用边界) 巩固巩固。

```rust
pub fn push(&mut self, elem: T) {
unsafe {
// 一开始就将 Box 转换成裸指针
let new_tail = Box::into_raw(Box::new(Node {
elem: elem,
next: ptr::null_mut(),
}));

if !self.tail.is_null() {
// 一开始就将 Box 转换成裸指针
let new_tail = Box::into_raw(Box::new(Node {
elem: elem,
next: ptr::null_mut(),
}));

if !self.tail.is_null() {
unsafe {
(*self.tail).next = new_tail;
} else {
self.head = new_tail;
}

self.tail = new_tail;
} else {
self.head = new_tail;
}

self.tail = new_tail;
}
```

Expand All @@ -126,7 +137,10 @@ pub fn pop(&mut self) -> Option<T> {
if self.head.is_null() {
None
} else {
let head = Box::from_raw(self.head);
let head;
unsafe {
head = Box::from_raw(self.head);
}
self.head = head.next;

if self.head.is_null() {
Expand Down