0%

第一阶段的Rustlings

关于第一阶段的Rustlings,还是花了很多时间去学习Rust。一开始是直接去看《Rust程序设计语言》,随后还看了《Rust圣经》,把一些较为简单的概念和程序过了一遍。可是发现做题时还是难以掌握,随后只能带着疑问和不懂的地方边做边查,做完一套后终于有点入门的感觉了,我感觉rust对我或者别的语言的用户来说,一大难点就是自造的概念太多了+ 第一次接触时的api暴露太多了,有一点不知如何下手。然后再结合上生命周期,就更难上手了。

rcore实验

Lab 1

这个实验主要是实现一个简单sys_task_info多任务系统. 通过这个实验, 了硬件是如何在不同的特权级之间切换的, 以及操作系统是如何管理这些特权级的,知道什么是系统调用和特权级的应用

Lab 2

lab2是实现在启用虚拟地址的情况下重写sys_get_time和sys_task_info, 并实现sys_mmap和sys_munmpa系统调用, 因为启用了分页机制, 学习到了地址空间的概念, 应用程序只需要关心自己的地址空间, 而不需要关心其他应用程序的地址空间, 在实现过程中我对操作系统对代码中的地址空间, 页表的地址转换有了更深的理解

Lab 3

lab3是实现sys_spawn和stride调度算法, 学习到了进程是如何创建的, 以及进程是如何执行的

Lab 4

lab4是实现硬链接和获取文件信息的系统调用, 需要对inode和disk_inode有较深的理解, 学习了文件系统是如何与物理存储设备交互的

Lab 5

lab5是实现死锁检测, 需要理解死锁检测算法 need矩阵

第一阶段

补充第一阶段的内容:主要就是学习rust的使用,基本上问题都能够解决

在阶段二让我对操作系统和rust有了更加深刻的理解

操作系统部分

其实我是有linux内核和驱动的开发经验的,所以对虚拟地址、物理地址、页表、等等知识都是有接触的,但是主要还是停留在书本或者内核提供的api,这五次作业,让我用rust这门最开始接触的语言来实现底层,也还是难度不小。

最开始的页表啊、映射啊、以及一些环境搭建还有git使用对我来说基本没有难度,但是到了第四个lab和第五个lab就开始难了。

文件系统:这个本身我对其就没有太清楚的了解过内部结构,只是会用,这次lab4的作业,强制我要去看源码实现,对超级区块,以及bitmap管理分配的索引,以及bitmap管理内容区块,再到系统层面通过OSInode来管理每个文件的inode,以及管理到物理磁盘上的inode,以及文件名啥的相互联系,让我从底层的磁盘到上层OS的管理链路有了比较清晰的认识,并且对rust的使用有了更加深刻的理解(没错,特指生命周期,和mut ref),因为这两个没少出现借用的问题。

死锁检测:这个部分也是耗时很长,其实我认为这部分的理解不难,因为我很早就接触了锁、信号量这些,我觉得这部分最难的在于调试。由于是并发编程,遇到的情况千奇百怪,以及难以定位。所以我写了很多的log,并且以非常人性化的输出来查看,虽然这部分耗时比较久,但是打好log对后续的开发是如虎添翼。也不会有陷入log中无法自拔的问题。并且通过实现了这个算法,算是开辟了新的知识点,以前从来没有想到还能死锁检测。

对同学的建议

总的来说难度不小,并且其实资料是比较有限的(对于无从下手的新手来说),所以如果卡关了还是要多去搜索资料,以及看源码(这个很重要),去看具体的实现,以及画流程图和结构体之间的关系图,以及标注重要的api(找到合适的api可以事半功倍)

对项目建议

总的来说操作系统的重点都有涉及,知识面还是很充足的!!

但是在编写过程中明显感觉到由于前向兼容导致测试用例的编译越到后期越慢,每次run光编译就会花费一分钟,其实可以优化makefile来单独编译某些测例来减少测试开发的时间。

以及最后两个lab难度上升有点大,并且文章 中是对功能的描述居多(很多对于实验有用的点会被淹没在其中)虽然在边做lab边反复查看资料时可以发现,但是对于没有接触过的同学可能很多api看过就没印象了,在后续做lab中也找不到,所以可以适当增加一下强调或者提示,来减少难度增加坡度。

最后还可以收集一下大家的调试方法,这样对于后续对debug无从下手的同学也有参考意义。

前言

因为我已经工作有12年了, Rust也写了有几万行, 所以第一阶段对我来说没什么难度. 但是我还是按照训练营的要求, 完成了rustlings的练习.

rustlings

rustlings的练习很简单, 但是对于新手来说, 是一个很好的入门练习. 通过这些练习, 可以很快的了解rust的基本语法和特性.

不过我仍然从中学到了一些新东西, 比如 BinaryHeap. 之前我在编写应用程序的时候一直用 Vec 来实现优先队列, 现在我知道了 BinaryHeap 这个更好的实现.

总结

理解了 Drop 就入门了 Rust.
理解了 Trait 就熟悉了 Rust.

前言

就Rust语言来说,我认为这是开创新时代的语言,一直在努力学习。
我自己学Rust语言的过程,分了三个阶段,最初纯粹是好奇。
用Rust自己写了一些小程序后,对Rust有了实际的体验,感觉体验很好、值得信赖。
于是有了更深入学习的想法,前面参加了InfiniTensor训练营,了解到使用Rust开发更复杂程序的方法。
现在参加操作系统训练营,是对自己更高的挑战。

开发一个操作系统内核是一个宏大的课题,需要认真的思考、深入地研究。训练营在短时间内整个拉了一遍,
给了学员一个宏观的体验,这非常宝贵,这是我参加训练营的原因。同时,在这个过程中,通过交流和学习,
也触发了我个人的深层思考,这对我个人尤为宝贵。
限于时间,我没法把所有问题思考透彻,但又不能感兴趣的问题轻易丢弃,于是写这篇总结,留待以后。
标题叫Something Not yet done,就是我想做、想探寻但还没有答案的东西。

基础阶段

内容

基础段主要涉及Rust语言的学习。

  • Rust语言的unsafe部分
  • Rust语言的异步和并行部分

Rust语言的unsafe部分

第一次涉及到unsafe部分代码的编写,经历了程序的崩溃,意识到unsafe的危险;到使用安全方法怎么也无
法实现想要的功能,明白了Rust的哲学,unsafe的重要性。从享受Rust的安全编程,转变为谨慎地编写unsafe
然后再享受Rust的安全编程,对于Rust的编程理念有了更近一步的了解。
但如何安全地编写unsafe,仍然有很多知识需要学习和实践,包括:

  • unsafe function
  • unsafe trait
  • unsafe extern

要完全掌握Rust,unsafe是必须跨越的一步。

Rust语言的异步和并行部分

对于如何编写高性能的Rust程序,还缺乏实践。

专业阶段

内容

专业阶段主要涉及对rCore的代码分析、学习,和部分功能实现。

  • 系统调用
  • 虚拟地址
  • 进程管理和调度
  • 文件系统
  • 并行控制

系统调用

这部分功能比较简单。

虚拟地址

引入虚拟地址后,所有系统调用的参数传递,都需要进行地址转换。目前都在系统调用处理函数中,复制粘贴
代码来实现,格外得丑陋。希望在第三阶段的时候,对这部分进行封装。

进程管理和调度

stride是比较简单的调度算法,希望在后面能够尝试将Linux的调度算法移植过来。

文件系统

在实现功能的过程中,在File trait中增加的一个方法。不知道有没有破坏原有的抽象,三阶段看看完整的
项目是如何解决File到Inode转换的。

并行控制

死锁检测的实现中,感觉对于列表的实现有点丑陋,目前可用的集合类就只有VecDeque,三阶段看看有没有
其他实现方式。

项目阶段

待补充。

rustlings 总结

Rustlings 是学习 Rust 编程语言的极佳练习工具,它包含了多个由浅入深的练习题目,帮助学习者快速掌握 Rust 的基础知识和重要概念。

1. 变量与可变性

  • Rust 中的变量默认是不可变的(immutable),即变量在声明后无法更改。要让变量可变,必须显式添加 mut 关键字。
  • 这种默认不可变性帮助开发者避免无意的状态变化,提高代码的安全性和可维护性。

2. 数据类型

  • Rust 是静态类型语言,编译器会在编译阶段检查数据类型。
  • Rust 支持多种数据类型,包括标量类型(整型、浮点型、布尔型、字符)和复合类型(元组、数组等)。

3. 所有权机制

  • Rust 的所有权系统是其内存安全性和性能的重要保障。
  • 每个值在同一时间只能有一个所有者,当所有者变量超出作用域时,内存会自动释放。所有权的转移、借用和引用(可变和不可变)是理解 Rust 内存管理的关键。

4. 借用与引用

  • 借用(Borrowing)允许在不转移所有权的情况下使用数据。
  • Rust 有严格的借用规则:在同一作用域中,只允许一个可变引用或多个不可变引用,确保内存安全。

5. 结构体与枚举

  • 结构体(Struct)用于将不同的数据组合成一个复合类型,枚举(Enum)用于定义一组可能的状态或值。
  • Rust 的枚举非常强大,支持绑定数据,并且可以与模式匹配一起使用,帮助更清晰地处理复杂的逻辑分支。

6. 模式匹配

  • match 表达式和 if let 是 Rust 中处理分支的主要工具,尤其是当处理枚举和结果类型(Result)时。
  • match 语法不仅简洁,还能避免遗漏某些分支,确保代码的健壮性。

7. 错误处理

  • Rust 提供了 ResultOption 类型来进行错误处理和空值处理。
  • 使用 unwrapexpectmatch 等方式处理这些类型,开发者可以编写出更健壮的代码,避免程序在运行时崩溃。

8. 所有权的移动与复制

  • 移动(Move):当变量的所有权被转移时,源变量将不可用。
  • 复制(Copy):对于实现了 Copy 特征的类型(如基本数据类型),赋值不会转移所有权,而是直接复制。

9. 特征

  • Rust 中的特征类似于其他语言的接口,用于定义一组方法签名,供结构体或枚举实现。
  • 特征使得 Rust 支持多态,通过泛型和特征约束实现代码的复用和接口一致性。

10. 智能指针

  • Rust 的标准库中提供了 BoxRcRefCell 等智能指针类型,帮助管理内存和共享数据。
  • Box 实现堆分配,Rc 实现引用计数,RefCell 提供运行时的可变性检查,用于实现更复杂的数据结构。

11. 并发编程

  • Rust 的所有权机制让多线程编程更加安全。
  • 使用 std::thread 库可以方便地创建线程,并且借助 ArcMutex 等类型来实现线程间的数据共享和同步。

12. 生命周期(Lifetimes)

  • Rust 使用生命周期注解来管理引用的生命周期,确保程序不会引用无效数据。
  • 生命周期的概念是 Rust 内存安全的重要组成部分,编译器会自动推断大部分生命周期,但有时需要显式标注。

OS 实现

第二阶段主要分为八个章节,每个章节层层递进,深入揭示操作系统的底层逻辑以及实现原理。

lab1

为了实现 sys_task_info 系统调用,首先在 TaskManager 中为任务控制块 (TCB) 扩展结构体,加入如下字段:sys_call_times:[u32;MAX_SYSCALL_NUM],然后在在mod.rs中增加increase_sys_call和get_sys_call_times函数,进而在syscall函数中调用increase_sys_call函数,

在系统调用处理逻辑中,维护当前任务的系统调用次数计数,每次进入系统调用时在数组中相应位置加一。在 sys_task_info 系统调用实现中,将当前任务的状态(应为 Running)、系统调用次数、以及通过 get_time() 获取的任务总运行时间写入 TaskInfo 结构体。

lab2

  • 完成sys_get_time和sys_task_info函数,需要定义一个translated_struct_ptr,它通过页表(PageTable)将一个指向结构体(*mut T)的指针翻译为对应的物理地址,并返回一个可变引用(&’static mut T),这样可以直接操作映射后的物理内存。在sys_task_info函数中,需要获取系统调用时间和任务运行时间,所以需要在task.rs中定义并实现它们。
  • 完成sys_mmap和sys_munmap函数,用于申请和释放虚拟内存映射。sys_mmap 通过指定的起始地址 start、长度 len 和内存页属性 port 来映射一段物理内存到虚拟地址空间。该函数会检查起始地址对齐情况、port 的合法性,并将内存页映射为可读、可写或可执行。sys_munmap 则用于取消内存映射,释放从 start 开始的一段虚拟内存。(注意,需要判断地址是否对齐)

lab3

  • 实现了自定义的spawn的系统调用来创建新进程,以便简化进程创建的过程而无需使用fork+exec的组合操作。通过sys_spawn,直接从指定的路径启动目标程序,成功返回子程序的进程id,否则返回-1。
  • 实现了stride调度算法,为每个进程设置优先级与其调度权重,使得系统资源能够更公平分配。stride调度通过设置初始优先级与动态步长(pass值),优先调度累计步长最小的进程,并对选中的进程步长进行累加调整,确保各进程的运行比例与优先级成正比。我还新增了 sys_set_priority 系统调用,以便动态调整进程优先级,增强调度灵活性。

lab4

在本次作业中,我实现了三个系统调用:linkat、unlinkat 和 fstat,以支持硬链接和文件状态获取。

  1. linkat:该调用用于创建一个文件的硬链接。它接收原有文件路径和新链接路径作为参数,并将新路径指向与原文件相同的磁盘块。在实现中,我确保在创建链接时不允许同名文件的存在,避免潜在的未定义行为。
  2. unlinkat:此调用用于删除文件的链接。当调用 unlinkat 时,如果文件的引用计数降至零,它将回收与文件关联的 inode 及其数据块。我的实现确保正确处理文件的彻底删除,维护文件系统的一致性。
  3. fstat:该调用获取指定文件描述符的状态信息。它将文件状态结构体填充以提供有关文件的详细信息,如大小、权限和时间戳等,便于用户或其他系统调用进行进一步处理。
    通过这三个系统调用的实现,我的文件系统支持了硬链接的创建与删除,以及文件状态的查询,从而增强了其功能和灵活性。

lab5

我实现的功能包括对进程和线程的资源管理,主要是通过互斥量(mutex)和信号量(semaphore)来控制并发访问。具体而言,为每个线程维护了四个关键数据结构:m_allocation 和 s_allocation 用于记录已分配的互斥量和信号量的数量,m_need 和 s_need 则用于跟踪线程尚需的资源数量。在系统调用中,加入了对死锁的检测逻辑,确保在尝试获取新资源之前检查当前资源的可用性。如果发现潜在的死锁情况,则会拒绝资源请求,并返回相应的错误代码。此外,还实现了调整资源需求的方法,以便在资源分配和释放时动态更新状态。

1
make -C /home/linux/vscode/arceos A=/home/linux/vscode/my_arceos_app ARCH=aarch64 LOG=debug SMP=1 run

U.1.0 HelloWorld

![![[Pasted image 20241111091146.png]]](<2024年开源操作系统训练营第三阶段总结-silent12rt/Pasted image 20241111091146.png>)
该图展示了一个应用程序(hello_world)在系统中各个模块(如axruntimeaxhalaxstdarceos)之间的结构和交互关系。以下是各个部分的功能说明:

  1. axhal(硬件抽象层):该层对硬件细节进行抽象,为更高层提供一个屏蔽底层硬件的基础,使上层不需要直接管理底层硬件。

  2. axruntime(运行时环境):该层管理应用程序的运行时环境,包括内存分配、线程调度和其他运行时服务,是应用程序正常运行的基础。

  3. ulib(axstd):这是一个标准库,为应用层提供通用功能和实用工具,可能包含基本的I/O操作、数据处理等辅助功能。

  4. api(arceos):这是与底层操作系统(ArceOS)的应用编程接口,允许应用程序执行系统级操作,如文件管理、进程间通信等。

  5. app(hello_world):这是用户的应用程序,利用axstdarceos提供的库和接口来执行特定任务。

  6. 执行流程

    • 左侧的准备环境(蓝色箭头)表示系统的准备阶段,在此阶段,配置和初始化必要的资源和环境。
    • 右侧的调用功能(橙色箭头)表示应用程序在运行时与axstdarceos进行的交互,通过这些库和API执行特定功能。

U.2.0 Collections

Buddy System(伙伴系统)

  1. 分配内存单元
    设置最小分配单元(通常是 2 的幂次方大小),而不是按1字节来分配。这种划分可以提高分配效率,并且降低管理开销。例如,如果分配单元是 8 字节,最小分配的内存块将是 8 字节。在 Buddy System 中,不同大小的块按 2 的幂次划分(即 8、16、32、64 等),每个大小被称为一个 order。每个 order 是一种特定大小的块。
  2. 分配过程
    • 寻找最小满足请求的块。当程序请求内存时,分配器首先确定需要分配的块的大小(例如 64 字节)。然后分配器会在内存池中找到最小的能满足此请求的 order 块(例如 128 字节的块,若没有 64 字节的块)。
    • 二分切割。如果找到的 order 大于所需的大小,那么分配器将不断地对该块进行 二分切割,直到得到匹配所需大小的块。
    • 返回分配的块:分配器返回一个与请求大小匹配的块,并将它从空闲列表中移除。此时,程序可以使用该块。
  3. 释放过程
    • 检查是否有空闲的邻居块:当程序释放某块内存时,分配器会检查该块是否有“伙伴”块(即同一级的邻居块)也是空闲的。两个邻居块的地址通常具有某种关系,使分配器可以根据地址快速定位伙伴块。
    • 合并到高 order:如果找到空闲的伙伴块,分配器会将两个相邻的空闲块合并成一个更大的块。这个合并过程会尽量继续进行,直到不能再合并为止。
    • 挂到 Order List:如果无法进一步合并,最终的空闲块会挂到相应的空闲列表(Order List)中,以备后续分配使用。

内存分配算法-Slab

![![[Pasted image 20241111191653.png]]](<2024年开源操作系统训练营第三阶段总结-silent12rt/Pasted image 20241111191653 1.png>)
分配过程

  1. 找到合适的OrderList
    根据请求的内存大小,找到合适的 OrderList。OrderList 会匹配内存大小,确保分配合适的 Slab。
  2. 从 Slab 的空闲块链表中获取 block
    • 从空闲块链表 (Free Block List) 中弹出一个 block,完成分配。
    • 如果空闲块链表中没有可用的 block,则进入下一步。
  3. 调用 BuddyAllocator 分配新块:
    • 当空闲链表中没有足够的块时,向 Buddy Allocator 请求一个较大的内存块。
    • 将分配到的较大内存块切分为符合 Slab 需求大小的 block,然后加入到该 Slab 的空闲块链表。
    • 最终,分配请求从空闲块链表中取出一个 block 返回。

释放过程

  1. 释放 block 到空闲块链表
    • 释放时,将 block 放回对应 Slab 的空闲块链表。
    • 这样,当后续需要分配类似大小的块时,可以直接从该空闲块链表中分配,避免重复分配和释放较大块的开销。
  2. 管理内存回收
    • 如果某个 Slab 变得完全空闲(即所有 block 都释放),可以选择将该 Slab 的内存归还给 Buddy Allocator,以释放更多内存供其他用途。

U.3.0 Collections

U.4.0 Collections

核心算法:context_switch

任务上下文Context: 保存任务状态的最小的寄存器状态集合。
![![[Pasted image 20241112144224.png]]](<2024年开源操作系统训练营第三阶段总结-silent12rt/Pasted image 20241112144224.png>)
ra: 函数返回地址寄存器,这个切换实现了任务执行指令流的切换。
sp: 任务即线程,这个是线程栈
s0~s11:按照riscv规范,callee不能改这组寄存器的信息,所以需要保存。

抢占式调度算法ROUND_ROBIN

在协作式调度FIFO的基础上,由定时器定时递减当前任务的时间片,耗尽时允许调度,一旦外部条件符合,边沿触发抢占,当前任务排到队尾,如此完成各个任务的循环排列。
![![[Pasted image 20241112151551.png]]](<2024年开源操作系统训练营第三阶段总结-silent12rt/Pasted image 20241112151551.png>)

抢占式调度算法CFS(Completely Fair Scheduler)

![![[Pasted image 20241112151735.png]]](<2024年开源操作系统训练营第三阶段总结-silent12rt/Pasted image 20241112151735.png>)

前言

我是一位已经参加工作有12年的资深工程师, 职业生涯中曾经担任过 CTO, 也做过总架构师. 精通 5+ 门编程语言, 对 10+ 门编程语言有过万行生产环境编码经验.
但因为自己毕业于一所大专院校, 在大专学习期间学校并没有开设过这些计算机系基础课程. 在多年工作中我时常好奇:

  1. 应用程序的内存是如何分配的
  2. 应用程序代码是如何启动的
  3. 应用如何与操作系统进行交互
  4. 操作系统是如何管理硬件资源的
  5. 多线程是如何实现的
    等等问题.
    抱着求知的心态, 我报名参加了这次的操作系统训练营.
    这些基本能力, 对应用开发者来说就像超市货架上每天都能“生长”出来的食物, 操作系统是如何把他们实现的, 我想要了解这个过程.

我曾在2021年参加过一次学堂在线的操作系统课程, 但是因为工作和家庭琐事繁忙, 最终没有完成. 这次我希望通过这次训练营, 继续学习操作系统的知识, 并且完成所有的实验.

我始终贯彻着一句话: 计算机是一门实践工程学科, 不管看的听的再怎么醍醐灌顶, 写不出来就是没学会.
学校的操作系统课程, 大多数都是讲理论, 缺乏实践. 这次训练营, 我希望能开发自己的内核程序, 并烧录到自己的硬件上运行.

第二阶段

Lab 1

这个实验主要是实现一个简单的多任务系统. 通过这个实验, 我理解了硬件是如何在不同的特权级之间切换的, 以及操作系统是如何管理这些特权级的.

Lab 2

这个实验启用了分页机制, 我学习到了地址空间的概念, 应用程序只需要关心自己的地址空间, 而不需要关心其他应用程序的地址空间. 同时我也学习到了内核是如何管理这些地址空间的.

Lab 3

进程: 学习到了进程是如何创建的, 以及进程是如何执行的.

Lab 4

文件系统: 学习到了文件系统是如何与物理存储设备交互的, 块存储设备是如何存储文件与数据的.

Lab 5

多线程: 学习到了操作系统是如何实现多线程的, 以及多线程之间如何通过锁来通讯.
通过课程实验: 我学习了如何用银行家算法检测死锁.

总结

通过这门课程我学习到了很多操作系统的基础知识, 包括:

  • 裸机程序是如何启动的
  • 应用程序内存是如何分配与隔离的
  • 操作系统是如何操作硬件的
  • 应用程序是如何与操作系统进行交互的
  • 文件系统是如何实现的
  • 等等…
    同时我也发现课程框架代码存在许多值得改进的地方, 所以我在尝试编写自己的内核程序.

阶段1:语言学习

rust 是一门非常有意思的语言,它吸收了很多现代编程语言的特性,特别是来自函数式编程的许多特性,比如 默认不可变,模式匹配,流 api,以及 trait,可以以一种不同的方式去抽象与编码。
rust 的“人体工程学”做的也非常不错,有许多语法糖与内置宏,匿名函数的写法也足够简洁,在学习过程中感觉非常有趣。

在语言学习过程中重点学习了基本的语法以及一些库函数的使用,对语言周边,比如 clippy 的使用还不够好,build.rs 也不太会写,多线程编程也不够熟练,希望接下来的学习当中能再注意一下重点学一下这些东西。

阶段2:rcore labs 学习

rcore 今年秋冬的任务是除了进程间通信以及io设备没有做过多要求,其余的每章都有一个编程练习,在我看来,编程练习的难度是适中的,但是依然要求完整的理解整个代码框架,对学习操作系统内核很有帮助。

前三章作为引子一步一步从裸机程序到一个批处理裸机程序的内核,后面几章的顺序是:虚拟内存(地址空间),进程,文件(持久化存储),再到并发。课程顺序与传统授课顺序不太一样,在我个人看来是一种由易到难的渐进学习过程:因为第八章的线程和并发编程真的感觉好难 debug 😂,在这章上浪费的时间也比较多。

印象最深刻的是对文件系统的讲解,将文件系统作为一个库抽象出来,内核也只是管理文件系统提供的 Inode 接口,以此来区分在内存中的 inode 和磁盘中的 inode,这样一层从 BlockDevice 到 FileSystem 再到 rcore-kernel 最后被封装为一些系统调用,这样层层抽象的写法看起来真的挺赏心悦目的哈哈,而且对知识的学习与综合起来也方便许多。

另外还有虚拟内存,内存模型也是内容量非常庞大的一章,需要理解 memory-set, map-aera, pagetable-entry, 以及物理地址和虚拟地址,物理页号和虚拟页号之间的关系,

抽象之下是和底层处理器的操作,内联汇编,riscv 库,以及 C ffi,rust 都支持的很好。处理 trap 的汇编函数也很有意思,以及一些 riscv csr,学习的同时也去了解了一下 riscv。不过本次学习,对rv要求的不是很多,更多的是以问答作业的形式去提问,不知道后面的阶段会不会有深入的机会。

2024二阶段总结

在这一阶段,我对我的学习可以划分两个比较明显的时期,一个是前期比较懵懂地入门,一个是中后期的速通。

Read more »

Rustlings

这是我第一次刷Rustlings,还是很有收获的。最后新增的一些算法题也很有意思,不过整体来说还是适合有Rust语法知识基础的人学习。最后几个算法题刷的很慢,我的数据结构和算法学的不是很好,在这里有学到很多。不过我也参考了许多资料。如果有人看的话,也算一点收获叭。整体来说Rust写起来很爽!

参考资料

Rust语法基础

初学者应该主要从三个方面了解Rust:Rust语法基础,Cargo以及Rust的标准库和官方文档。

Rust 程序设计语言 - Rust 程序设计语言 简体中文版

这是社区推荐的的The Rust Programming Language的中文翻译版本。主要讲Rust语法基础,国内有开源作者撰写了Rust语言圣经两本书的内容比较相似,后者语言比较生动,内容也比较丰富,前者的话语言精炼一些,个人比较推荐去读前者,读不懂的时候再去看Rust语言圣经的版本,会有新的收获。

The Cargo Book

Introduction - The Cargo Book

The Cargo Book是关于Cargo的一本书,初学者可能只会使用到Cargo的一少部分命令和参数,但实际上,Rust受到广泛关注的一个原因,就来自于强大的构建和包管理工具Cargo,值得注意的是这本书的中文翻译版本最后的更新时间是2019年,相关的内容和英文最新版差别比较大,最好读英文版本。

Rust标准库文档

List of all items in this crate

Rust的标准库文档涵盖了基础阶段大部分的内容,结构体、宏、智能指针等等都在标准库文档中有详细的说明,Rust程序相比其他许多语言确实比较在学习和编写上难度更大 ,但是Rust设计者们也在极力减少开发者的心智负担,对于一些数据类型和结构,标准库中定义了一些好用的方法和属性,方便大家学习和使用。另外,标准库中也定义了一些基本的API接口,方便开发。总之Rust标准库是一座宝库。

Rust

crates.io: Rust Package Registry

crate.io是提供了诸多Rust开发者开发的库,可以直接在cargo.toml里面配置库名和版本就能使用,很方便,基础阶段Rust标准库文档是小宝库,在后续进阶开发阶段,crate.io就是名副其实的大宝库。言下之意是,基础阶段暂时不用看这个。

Youtube

Rustlings 5.0 | Intro | Learn Rust Interactively

**目前国内的Rust学习资源还在初级阶段,B站上暂时没有很完善的教程,推荐一个油管博主的视频,讲到比较陌生不好理解的地方,博主会把Rust基础教程和标准库文档贴出来,对着讲解,还是很有收获的,还能教你怎么快速找到自己需要查的知识点。但是这个博主是之前录的视频,没有训练营版本Rustlings最后一些练习的讲解。