GrowGen | 整

Learning Rust with entirely too many linkd lists

J.Gong

2021-01-13

2.85min

Learning Rust with entirely too many linkd lists

序言

基础

  • 指针

    • &
    • &mut
    • Box
    • Rc
    • Arc
    • *const
    • *mut
  • 所有权

  • 关键字

    • struct
    • enum
    • fn
    • pub
    • impl
  • 模式匹配

  • 测试

  • 简单的unsafe模式

驳斥链表

  • 性能不总是重点
  • 链表的处理可以是O(1)的
  • 无需复杂度均摊
  • 节省空间
  • 函数式开发一直使用链表
  • 利于并行开发
  • 内核开发、嵌入式开发使用链表
  • 插入删除不会让迭代器失效
  • 简单且易于教学

一个糟糕的栈

  • 布局

    • List a = Empty | Elem a (List a)

    • 布局一: enum List { Empty, Box }

      • 必须用Box分配堆内存,否则编译器不知道如何分配栈内存
      • 可以发现链表最后多余一个Empty,则更改布局二
    • 布局二:: enum List { Empty, More(Box) } struct Node { elem: i32, next: List }

  • 创建

    • impl List { pub fn new() -> Self { List{ head: Link::Empty } } }
  • 所有权入门

    • self - 值

      • 完全复制的值,函数值执行完会被销毁
    • &mut self 可变引用

      • 完全控制值所在地址
      • 不能给值增加引用
    • &self 不可变引用

      • 完全取得值所在地址,但不能更改
  • push

    • 因为&mut self.head不能增加引用,必须先用mem::replace替换原来引用来释放引用
  • pop

    • 未完成的函数可以使用unimplemented!宏来避免编译报错
    • match关键字也如函数一样存在值引用的问题
  • 测试

    • assert_eq!宏来处理断言
    • #[cfg(test)]注释来表明模块仅用于测试环境
    • #[test]注释用于表明函数用于测试
    • 模块内需要引用外部的元素(use super::List;)
  • Drop

    • Box的析构过程无法形尾递归调用,析构时会爆栈

一个不错的栈

  • 使用Option代替Link

    • take方法替代mem::replace
    • map方法替代match
  • 支持泛型

    • impl
  • peek

    • take方法会把数据取出并把原来的位置用None补充
    • as_ref会取得Option中的不可变引用
    • as_mut会取得所在内存的可变引用
  • 迭代器

    • 简单迭代

      • pub trait Iterator { type Item; fn next(&mut self) -> OptionSelf::Item; }
    • 不可变迭代

      • 显式声明所有权

        • 一个函数引入两个以上引用时
        • 一个泛型结构体
        • 编译器会提醒添加
      • 解开Box可以使用*操作来deRef,如 *node

    • 可变迭代

列表

Box只能实现单指针

Rc实现引用计数

  • use std::rc::Rc

  • 使用clone方法

  • Option

    • map: Option -> Option
    • and_then: Option -> T.
    • as_ref: &Option -> Option<&T>
    • as_mut: &mut Option -> Option<&mut T>

Arc线程安全的引用计数

  • Send trait: 可以移动到别的线程
  • Sync trait:可以被多个线程查看
  • Rc实现是基于Cell的
  • Arc基于Atomic

队列

一个不好但是Safe的队列

  • RefCell需要动态借用

    • borrow(self) -> Ref
    • borrow_mut(self) -> RefMut
    • into_inner()可以取得包裹的值
    • 虽然Ref和RefMut表现和&和&mut相同,但不能由Ref转换到&
  • Rc

    • 解开Rc需要使用try_unwrap()之后再unwrap()
    • Rc解决不了环形引用

一个可以但是unsafe的队列

  • The Rustonomicon https://doc.rust-lang.org/nightly/nomicon/
  • *mut T
  • std::ptr
  • 具体unsafe的部分只靠这一个例子还搞不懂 主要先摆正姿态,Unsafe其实并不是不好,只是此时编译器不做检查

总结

这次是彻底了解了Rust的所有权生存期的内容,虽然最后unsafe相关内容还是不清楚,单已经有很大进步了。

© 2025 我的技术博客. 保留所有权利.

使用 Astro.build + Mantine 构建 | 部署在 Vercel