0%

第一阶段 - Rust学习

0 前言

Rust作为rCore操作系统的开发语言,学习并掌握它对于后面学习rCore OS是非常重要的(关于我Rust学了个大概就去硬啃rCore差点自闭这件事)。

这次训练营也是我二刷了,上次23秋季由于被学校抓去打互联网+等比赛了,🤦‍♂️实在是没有时间弄了,进了二阶段就没然后了。

翻车gif

一阶段时间过的好快,感觉还没学多少就过去了(时间都用去debug操作系统大赛的fatfs了🤦‍♂️)。所以总结的内容就比较普普通通了,各位大佬见谅🙏。

1 环境与工具软件等

由于本人并不是CS相关专业,过去主攻的是EE,所以CS里面的很多东西过去都没接触过。从23年秋季第一次接触训练营开始到现在,接触到了很多过去没有用过的工具软件以及一些开发环境,在此简单的列举了一些。

1.1 git和github

是的,你没有看错。我之前真没怎么用过git和github。一方面原因是,上大学后搞的都是嵌入式裸机的开发,远古单片机IDE(Keil)不支持高级的代码版本管理,加上我的学习路线上也没碰到过使用代码版本管理,索性代码直接放本地(别人要的话就u盘拷贝🤦‍♂️),就很少用git去把代码放仓库(之前实习时迫不得已去折腾了下)。另一方面是,git和github有些时候真的太卡了(之前不会挂代理也不敢挂梯子)。

keil

不过,现在熟悉了git的各个命令后,配合上github去做项目的代码版本管理是真爽呀。

胡桃摇

个人过去常用的git命令和个人理解如下:

1
2
3
4
5
6
7
8
9
git clone 			// 将repo(仓库)克隆到本地
git pull // 合并远程repo的更新到本地
git add . // 将更改的文件放入暂存区
git commit -m "<message>" // 创建一个新的提交,-m 后便是提交的消息
git push // 将提交推到远程仓库
git branch // 查看现有的分支
git branch <new_branch> // 创键新的分支
git checkout <branch> // 切换到某分支
git status // 查看本地仓库状态

还有一些比如本地新建的分支需要推到远程、放弃某文件的修改等命令,就没去记了。我是做相关操作的时候,看一下报错建议的命令或在搜一下、问一下gpt,然后改一下。

另外初次使用可能需要配置用户信息:

1
2
git config --global user.name "Your Name"
git config --global user.email your.email@example.com

1.2 Linux操作系统(Ubuntu、CentOS)

虽说之前玩jeston和个人博客的时候也用过,但是基本上就是靠readme+baidu+CtrlCV+GPT(而且用了就忘),这次也算是又学习并加深了了解吧。这里就简单的列一下这期间用到的还记得的命令吧(大佬们清点喷555)

派蒙抱大腿

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ls                      	# 列出当前目录下的文件和文件夹
cd [目录名] # 改变当前目录
sudo [命令] # 以超级用户身份执行命令
sudo apt install [包名] # 以超级用户身份通过apt安装软件包
apt-get install [包名] # 通过apt-get安装软件包
touch [文件名] # 创建一个空文件或修改文件的时间戳
vim [文件名] # 打开文件进行编辑
rm [文件名/目录名] # 删除文件或目录
make # 用于编译程序的命令
cp [源文件/目录] [目标文件/目录] # 复制文件或目录
mv [源文件/目录] [目标文件/目录] # 移动或重命名文件或目录
mkdir [目录名] # 创建一个新的目录
rmdir [目录名] # 删除一个空目录
pwd # 显示当前工作目录的路径
cat [文件名] # 查看文件内容
file [文件名] # 查看文件信息
tar [选项] [文件名] # 打包或解包文件
gzip [文件名] # 压缩文件
gunzip [文件名] # 解压缩文件
wget [URL] # 从网络上下载文件
curl [URL] # 传输数据的工具,支持多种协议
ssh [用户名]@[IP地址] # 通过SSH协议远程登录到另一台计算机
scp [源文件/目录] [用户名]@[IP地址]:[目标路径] # 通过SSH远程拷贝文件
df -h # 显示磁盘使用情况
du -h [文件名/目录名] # 显示文件或目录的磁盘使用情况
free -m # 显示内存使用情况
top # 显示实时的系统进程信息
ps # 显示当前进程的快照
kill [进程号] # 结束一个进程
logout # 注销当前会话
reboot # 重新启动计算机
shutdown -h now # 立即关机
fdisk # 一个用于磁盘分区的程序,可以创建、删除、修改和重新组织分区表
losetup # 用于设置和控制Loop设备,它可以将一个文件模拟成块设备,常用于挂载文件系统镜像

1.3 RustRover

强烈推荐,我刚开始是用的VSCode+RA插件或Vim+YouCompleteMe。后来换成rr后,感觉开发真的舒服了好多。一是因为二阶段写OS,在ubuntu里我用的VSCode写一会就会崩,比较卡。用Vim的话,代码文件一多切来切去麻烦的很;二是因为他的各个界面和PyCharm、IDEA是一样的,上手很快;三是多了很多有用的功能,比如你use了某个外部creat,rr会自动帮你在cargo.toml中加上依赖。

RustRover下载地址:https://www.jetbrains.com/zh-cn/rust/

Linux环境安装步骤:

1
2
3
4
5
6
7
1. 下载
2. cd到下载的路径
3. 解压下载的安装包:
4. cd到解压的路径
5. cd bin
6. ./rustrover.sh
7. 勾选一些东西确认安装后,等待片刻,便会进入到欢迎界面

在欢迎界面左下角点击设置图标,再点击(Create Desktop Entry)将rustrover添加到桌面目录。之后便可以使用了。

xiao

2 Rust知识

2.1 Rust学习资料

1.Rust 中文圣经

2.Rust 程序设计语言

3.Rust 中文文档汇总

4.Rust 官方文档中文翻译

5.Rust 半小时学习
半小时看不完呀!

派蒙吃惊

2.2 个人觉得Rust比较有意思的知识点

2.2.1 所有权(Ownership)和生命周期(Lifetimes):

  • Rust的所有权和生命周期机制,可以防止诸如空悬指针、缓冲区溢出等内存安全问题。
  • 在Rust中,每个值都有且只有一个所有者。
  • 而在C语言中,并没有所有权概念,内存管理完全由程序员负责,这就可能导致内存泄漏和野指针等问题。
    1
    2
    3
    4
    5
    6
    // Rust
    {
    let s1 = String::from("hello");
    let s2 = s1;
    // 此时 s1 已经失效,不能被使用
    }
    1
    2
    3
    4
    // C
    char *s1 = "hello";
    char *s2 = s1;
    // 此时 s1 和 s2 都指向相同的内存

    2.2.2 借用检查(Borrowing):

  • Rust的数据借用可以允许多个读访问,但只要有一个可变借用,就不能有其他读或写访问。
  • C语言没有这样的机制,因此需要手动管理指针和数据的共享。
    1
    2
    3
    4
    5
    6
    7
    8
    // Rust
    {
    let mut s = String::from("hello");
    {
    let r1 = &mut s;
    // 在此作用域内,不能借用 s 的其他引用
    } // r1 超出作用域,s 可以被再次借用
    }
    1
    2
    3
    4
    // C
    char s[] = "hello";
    char *p1 = s;
    char *p2 = s; // p1 和 p2 都指向相同的内存

    2.2.3 模式匹配(Pattern Matching):

  • Rust提供了强大的模式匹配功能,可以用于枚举、结构体、元组和字面量等。
  • C语言没有内置的模式匹配功能,通常需要使用switch语句和多个if-else链来实现。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // Rust
    enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
    }
    let coin = Coin::Penny;
    match coin {
    Coin::Penny => println!("Penny"),
    Coin::Nickel => println!("Nickel"),
    Coin::Dime => println!("Dime"),
    Coin::Quarter => println!("Quarter"),
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // C 
    switch (coin) {
    case PENNY:
    printf("Penny");
    break;
    case NICKEL:
    printf("Nickel");
    break;
    case DIME:
    printf("Dime");
    break;
    case QUARTER:
    printf("Quarter");
    break;
    }

    2.2.4 并发(Concurrency):

  • Rust提供了安全并发的工具,如std::threadArc(原子引用计数)和Mutex(互斥锁)。
  • C语言标准库没有内置的并发工具,通常需要使用操作系统提供的线程库(如POSIX线程)和同步原语。
    1
    2
    3
    4
    5
    6
    // Rust
    use std::thread;
    let handle = thread::spawn(|| {
    // 在新线程中运行的代码
    });
    handle.join().unwrap();
    1
    2
    3
    4
    5
    6
    7
    // C 
    pthread_t thread;
    int status = pthread_create(&thread, NULL, &thread_function, NULL);
    if (status != 0) {
    // 错误处理
    }
    pthread_join(thread, NULL);

    2.2.5 错误处理(Error Handling):

  • Rust使用ResultOption类型来处理可能的错误或空值,这鼓励开发人员进行显式的错误处理。
  • C语言通常使用整数错误码和返回值,这可能导致错误被忽略或错误处理。
    1
    2
    3
    4
    // Rust
    fn open_file(file_name: &str) -> Result<File, io::Error> {
    File::open(file_name)
    }
    1
    2
    3
    4
    5
    6
    7
    8
    // C
    int open_file(const char *file_name) {
    FILE *file = fopen(file_name, "r");
    if (!file) {
    return -1; // 返回错误码
    }
    return 0; // 表示成功
    }

    3 总结

    说来惭愧,这次训练营第一阶段大部分时间花在折腾OS大赛上了。本来到rCore的ch7时都挺顺利的,结果尝试去运行OS大赛的FAT32镜像里的测例就碰壁了。先是easyfs和fat32不是一个东西,得把照着rCore写的OS的fs换成支持fat32的,瞎折腾了两周总算是能读取fat32里的文件了。然后又发现大赛OS的elf文件导入OS运行又有问题,瞎折腾也搞不出来了(基础不牢靠,不懂为啥会loadpage Fault),索性打算重新复习。

这次训练营又学到了很多新的知识,不过也能很清楚地感觉到掌握的不牢靠,后面还需不断加强巩固。同时我也知道了如果自己后面想往OS方向发展,还有很多需要去学习的。说实话,刚开始搞rCore的时候感觉还挺好的,而后到了ch4后,计组等知识的欠缺就很致命了,搞的差点放弃了(fat32那也是,不过好在搞出来了)。然后到了运行OS大赛的elf这就真搞不懂了,只能试着去好好复习下Rust、看看计组、CSAPP等后,再来看看了。

感激社区提供了这样一个学习平台,它为我打开了一扇探索操作系统奥秘的大门。希望后续的学习我还能够坚持下去吧!

npn

4 图片记录

1

照着rCore写的FeatOS移植FAT32文件系统成功

2024春操作系统训练营一阶段总结

水群的时候看到了别人分享的邀请链接,于是就报名了训练营

刚接触rust,很多东西理解起来很困难,尤其是lifetime和闭包、迭代器这些内容。

虽然写完了rustling,但还是有许多细节掌握得不够熟练,最后那十道algorithm一做一个不吱声🤡

参考的书籍有 rust程序设计语言 rust语言圣经

以及 rust by examplecrates.io 我不太会用😅)

对了,rustling里面好像没有异步,记得去补一下

希望下个阶段顺利🦀🦀

2024 春夏季训练营记录

说明

本文为训练营的每日实践记录索引,主要为按日期较随意地写下每天的记录与想法。

同时还包含对其他资料、笔记的索引。

更详细的记录在 github 仓库里 https://github.com/hehepig166/2024-OS-camp-notes

工具与资料

训练营社区 https://opencamp.cn/os2edu/camp/2024spring/

Github LearningOS https://github.com/Learningos

Open-Source OS Training Comp 2024 https://github.com/LearningOS/rust-based-os-comp2024

日历

04-01 04-02 04-03 04-04 04-05 04-06 04-07 (开营)
04-08 (第一阶段) 04-09 04-10 04-11 04-12 04-13 04-14
04-15 04-16 04-17 04-18 04-19 04-20 04-21
04-22 04-23

04-07

群公告
欢迎大家加入春夏季操作系统训练营!
4月7日正式开营,已报名的同学请及时学习导学视频内容!
网址:https://opencamp.cn/os2edu/camp/2024spring/stage/0?tab=video

在训练营常见问题Q&A文档https://docs.qq.com/doc/DY3VMc0tOc29KTWZ5 中,对于本期训练营有一些基本问题的介绍,也可以在群里询问

2024春夏季训练营启动仪式回放
录制文件:https://meeting.tencent.com/v2/cloud-record/share?id=95ecb9c0-64f2-4934-a671-78474f735af2&from=3&record_type=2
密码:0407

  • 开营仪式

    • rustlings -> Rust 学习

    • rcore -> Rust 重写内核实验

    • ArceOS -> 组件化 OS 项目

之前几周已经开始学习 Rust,做了 rust-lang 下的 rustlings

rust-lang::rustlings https://github.com/rust-lang/rustlings

我的解答与极其简陋随性的学习日志 https://github.com/hehepig166/my-solution-to-rustlings

(主要是 Rust 资料实在是太多了,我就只写一点关键词提一下记忆即可)

配置了一下 wsl

04-08

@所有人  各位同学,第一阶段“Rust编程语言 & Rustlings答疑”第一次课程将于今晚8点开始,今晚的主要内容为Rustlings练习入门、基本数据类型,slice类型,所有权等,总共一个课时,请大家预留时间,按时进入课堂!!

上课方式:点击 https://opencamp.cn/os2edu/camp/2024spring/stage/1 链接,签到并进入课堂进行直播上课

https://learningos.cn/rust-rustlings-2024-spring-ranking/

https://github.com/LearningOS/rust-rustlings-2024-spring-hehepig166

使用 ssh 链接 clone,用 ssh 鉴权

wsl2 /mnt/ 下 rustlings 更新编译可能会出问题,开发最好不要在 /mnt 目录下操作

module 的 pub 关键字只往上 pub 一层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
mod delicious_snacks {
// TODO: Fix these use statements
pub use self::fruits::PEAR as fruit;
pub use self::veggies::CUCUMBER as veggie;

mod fruits {
pub const PEAR: &'static str = "Pear";
pub const APPLE: &'static str = "Apple";
}

mod veggies {
pub const CUCUMBER: &'static str = "Cucumber";
pub const CARROT: &'static str = "Carrot";
}
}

fn main() {
println!(
"favorite snacks: {} and {}",
delicious_snacks::fruit,
delicious_snacks::veggie
);

// let a = delicious_snacks::fruits::PEAR; // 无法访问
let b = delicious_snacks::fruit; // 可以访问
}

04-09

std::f64::NAN

Rust 中两个 NAN 是不相等的,要判断一个浮点数是不是 NAN,可以用 .is_nan() 函数来判断。

完成了 rust-lang 里的 rustlings。

在 Rust 中,? 是一个简便的错误处理操作符,通常用于简化对 ResultOption 类型的值进行处理的代码。它的作用是在操作成功时返回成功的结果,如果遇到错误则将错误提早返回。

在函数中使用 ? 时,该函数的返回类型必须是 ResultOption。如果表达式的结果是 Ok(对于 Result 类型)或 Some(对于 Option 类型),则 ? 会将其中的值提取出来并返回;如果结果是 ErrNone,则整个函数会提前返回并将 ErrNone 作为整个函数的返回值。

04-10

@所有人 各位同学,第一阶段“Rust编程语言 & Rustlings答疑”第二次课程将于今晚8点开始,今晚的主要内容为Rustlings答疑,总共一个课时,请大家预留时间,按时进入课堂!!

上课方式:点击 https://opencamp.cn/os2edu/camp/2024spring/stage/1 链接,签到并进入课堂进行直播上课。

如果同学们有什么问题也可以在问题收集页面https://docs.qq.com/doc/DSXFzRkdodExxQUVO给老师提一下哦~

rustlings test 章节

  • 条件编译

#[cfg()]

cfg() 可以接受一些不同的条件,用于控制编译时的行为。这些条件可以是 Rust 编译器理解的一些特定标识符,也可以是自定义的条件。下面是一些常见的 cfg() 条件:

  • target_os: 目标操作系统,如 "windows", "linux", "macos" 等。
  • target_arch: 目标架构,如 "x86", "x86_64", "arm" 等。
  • target_env: 目标环境,如 "gnu", "msvc", "musl" 等。
  • target_pointer_width: 目标指针宽度,如 "32", "64" 等。
  • feature: 启用的特性,如 "myfeature"
  • any(): 如果任一条件为真则为真,语法为 cfg(any(condition1, condition2, ...))
  • all(): 如果所有条件为真则为真,语法为 cfg(all(condition1, condition2, ...))
  • not(): 取反,语法为 cfg(not(condition))
  • 自定义条件:你可以在 build.rs 或者 Cargo.toml 中定义自己的条件,然后在 cfg() 中使用。

这些条件可以根据实际需要组合使用,以便根据不同的情况编译不同的代码。

  • 外部链接 FFI(Foreign Function Interface)

extern

这段代码指定 my_demo_functionmy_demo_function_alias 从符号表中找名字为my_demo_function的函数链接。

而在 Foo::my_demo_function 中又指定了 #[no_mangle] ,即在编译后的目标文件中的符号名称可见并保持不变,被上面两个 extern 找到并使用。

注意这里利用这个东西,使这个函数的的 private 属性失效了。 FFI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// tests9.rs


extern "Rust" {

#[link_name = "my_demo_function"]
fn my_demo_function(a: u32) -> u32;

#[link_name = "my_demo_function"]
fn my_demo_function_alias(a: u32) -> u32;
}

mod Foo {
// No `extern` equals `extern "Rust"`.
#[no_mangle]
fn my_demo_function(a: u32) -> u32 {
a
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_success() {
// The externally imported functions are UNSAFE by default
// because of untrusted source of other languages. You may
// wrap them in safe Rust APIs to ease the burden of callers.
//
// SAFETY: We know those functions are aliases of a safe
// Rust function.
unsafe {
my_demo_function(123);
my_demo_function_alias(456);
}
}
}
  • 分析 traits

    parse() 返回一个 Result<i64, xxxErr> 类型的东西,然后 ? 操作符对它进行处理,要是是 i64,就传给 x 然后正常继续,要是是 Err 就提前结束当前 main() ,调用 from 方法把 Err 自动转成 Box 作为 main 的返回结果?

traits 类似 C++ 中的虚基类和虚函数

1
2
3
4
5
6
fn main() -> Result<(), Box<dyn error::Error>> {
let pretend_user_input = "42";
let x: i64 = pretend_user_input.parse()?;
println!("output={:?}", PositiveNonzeroInteger::new(x)?);
Ok(())
}
  • algorithm

区别 ref mut rootmut &root

04-11

rustlings algorithm5 bfs, algorithm6 dfs

“闭包”

04-12

@所有人 各位同学,第一阶段“Rust编程语言 & Rustlings答疑”第三次课程将于今晚8点开始,今晚的主要内容为crate,option,trait和泛型及生命周期,总共一个课时,请大家预留时间,按时进入课堂!!

上课方式:点击 https://opencamp.cn/os2edu/camp/2024spring/stage/1 链接,签到并进入课堂进行直播上课。

如果同学们有什么问题也可以在问题收集页面https://docs.qq.com/doc/DSXFzRkdodExxQUVO给老师提一下哦

rustlings algorithm7,8 stack, algorithm9 heap, algorithm10 graph

rustlings 完成了

继续学习rust生命周期

表达式 vs. 语句

super::

泛型, trait, 生命周期

trait 作为参数,可以指定多个trait

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 以下两个代码作用相同

pub fn notify(item: &impl Summary) { // item 为包含了Summary trait的一个引用
println!("Breaking news! {}", item.summarize());
}

pub fn notify<T: Summary>(item: T) { // item 为包含了Summary trait的一个引用
println!("Breaking news! {}", item.summarize());
}

// 多个 trait
pub fn notify(item: &(impl Summary + Display));
pub fn notify<T: Summary + Display>(item: &T);

// where
// 以下两个代码效果相同
fn fun<T: Display + Clone, U: Clone + Debug>(t: &U, u: &U) -> i32 {}

fn fun<T, U>(t: &T, u: &U) -> i32
where
T:Display + Clone,
U: Clone + Debug,
{

}

引用的生命周期

做一做 rust quiz

04-13

使用工具 rustfmt 可以自动将代码格式化。有助于分析代码。

代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
macro_rules! m {
($($s:stmt)*) => {
$(
{ stringify!($s); 1 }
)<<*
};
}

fn main() {
print!(
"{}{}{}",
m! { return || true },
m! { (return) || true },
m! { {return} || true },
);
}

这个是纯秀语法,没实际意义。

上面定义了一个宏规则 m

$()* 代表匹配一个或多个。

$s:stmt代表 s 是一个 statement。

=> {} 表示匹配到模式后要展开成的代码块规则。

$()<<* 表示对每个 statement 得到的代码块用 << 连接。

关键在于分析三行代码中各自有几个 statement。

第一个 return || true,是一个返回闭包 || true 的 return 语句。

第二个 (return) || true,是一个逻辑或语句。(虽然过不了编译,但是后面是转成字符串所以没事)。

第三个 {return} || true 是两个语句,一个是 {return} 语句块,另一个是 || true 闭包。

展开后,我的理解是这样:

1
2
3
4
5
6
7
8
fn main() {
print!(
"{}{}{}",
{ "return || true"; 1 },
{ "(return) || true"; 1 },
{ "{return}"; 1 }<<{ "|| true"; 1 },
)
}

04-14

继续看看 rust quiz

04-16

去看了吉卜力展

04-17

rust quiz

rcore 实验一

学习:Rust 生命周期

  • 无界生命周期 unsafe

  • 生命周期约束 HRTB

    • 'a: 'b 表示 'a 至少活得跟 'b 一样久

    • T: 'a 类型 T 必须比 'a 活得久

  • 生命周期与子类型

    • 子类型至少比父类型大
  • 引用的生命周期:从借用处开始,直到最后一次使用的地方

  • reborrow

    • let mut p = Point {x: 0, y: 0};
      let r = &mut p;
      let rr: &Point = &*r;
      <!--6-->
      
      * >清空内存前,我们插入了一条奇怪的汇编指令 `fence.i` ,它是用来清理 i-cache 的。 我们知道, 缓存又分成 **数据缓存** (d-cache) 和 **指令缓存** (i-cache) 两部分,分别在 CPU 访存和取指的时候使用。 通常情况下, CPU 会认为程序的代码段不会发生变化,因此 i-cache 是一种只读缓存。 但在这里,我们会修改会被 CPU 取指的内存区域,使得 i-cache 中含有与内存不一致的内容, 必须使用 `fence.i` 指令手动清空 i-cache ,让里面所有的内容全部失效, 才能够保证程序执行正确性。
  • 特权级切换

    • 硬件机制
      • U/S 特权级
      • 相关 CSR
        • sstatus
        • spec
        • scause
        • stval
        • stvec
    • 用户栈、内核栈
    • trap 管理
  • 荣誉准则
  1. 在完成本次实验的过程(含此前学习的过程)中,我曾分别与 以下各位 就(与本次实验相关的)以下方面做过交流,还在代码中对应的位置以注释形式记录了具体的交流对象及内容:

    《你交流的对象说明》

  2. 此外,我也参考了 以下资料 ,还在代码中对应的位置以注释形式记录了具体的参考来源及内容:

    《你参考的资料说明》

  3. 我独立完成了本次实验除以上方面之外的所有工作,包括代码与文档。 我清楚地知道,从以上方面获得的信息在一定程度上降低了实验难度,可能会影响起评分。

  4. 我从未使用过他人的代码,不管是原封不动地复制,还是经过了某些等价转换。 我未曾也不会向他人(含此后各届同学)复制或公开我的实验代码,我有义务妥善保管好它们。 我提交至本实验的评测系统的代码,均无意于破坏或妨碍任何计算机系统的正常运转。 我清楚地知道,以上情况均为本课程纪律所禁止,若违反,对应的实验成绩将按“-100”分计。

04-23

Rust 学习

  • 闭包(匿名函数)

    • 本质:拥有可能关联上下文的匿名函数体

    • 允许捕获被定义时所在作用域中的值(不像函数,必须显式传参)

    • fn add_one_v1     (x: u32) -> u32 { x+1 }
      let add_one_v2 =  |x: u32| -> u32 { x+1 };
      let add_one_v3 =  |x|             { x+1 };
      let add_one_v4 =  |x|               x+1  ;

      后面两个要编译必须使用。

    • 使用 move 强制获取所有权

    • Fn trait

      • FnOnce
      • FnMut
      • Fn
  • 智能指针

    • Box -> 将值放在堆上而非栈上
      • 针对编译时位置大小的类型
      • 有大量数据并确保数据不被拷贝的情况下转移所有权时
      • 拥有一个值并只关心它的类型是否实现了特定trait而非具体类型时
      • Deref trait
    • Rc -> 引用计数
      • clone
      • 克隆 Rc<T> 会增加其引用计数
      • 不可变引用
    • RefCell -> 内部可变性指针
      • Interior mutability
        • 该数据结构中使用了 unsafe 代码来模糊 Rust 通常的可变性和借用规则
      • 任意时刻,只能拥有一个可变引用或任意数量的不可变引用之一
      • 引用必须总是有效的
  • async

Rust学习总结报告

Rust是一种注重安全、性能和并发性的系统编程语言。在过去的几周里,我深入学习了Rust语言,对其有了更深入的了解。本报告将总结我所学习的Rust知识点,包括所有权、借用、生命周期、类型系统、模式匹配、错误处理、并发编程等。

1. 所有权

Rust的核心特性之一是所有权(Ownership),它控制了程序中的资源分配和释放。所有权规则包括三条:每个值都有一个变量,称为其所有者;同一时间内只能有一个所有者;当所有者离开作用域时,值将被丢弃。所有权机制有助于避免内存泄漏和数据竞争问题。

2. 借用

借用(Borrowing)允许我们在不转移所有权的情况下访问数据。Rust通过两种借用方式来实现:可变借用(&mut T)和不可变借用(&T)。借用规则包括:同一时间内只能有一个可变借用或多个不可变借用;借用者不能超过所有者的生命周期。

3. 生命周期

生命周期(Lifetimes)是Rust确保引用有效性的关键概念。Rust通过生命周期参数(如’a、’b等)来标注引用的存活时间。生命周期的主要作用是防止悬垂引用和数据竞争。在函数和结构体定义中,我们需要为引用参数和字段指定生命周期参数,以告诉编译器引用之间的关系。

4. 类型系统

Rust的类型系统非常丰富,包括标量类型、复合类型、自定义类型等。标量类型包括整数、浮点数、布尔值和字符;复合类型包括元组、数组、切片和字符串;自定义类型包括结构体、枚举和联合。Rust还提供了类型推导、类型别名、泛型等特性,方便开发者编写灵活、可重用的代码。

5. 模式匹配

模式匹配(Pattern Matching)是Rust中一个强大的控制流和数据处理工具。通过模式匹配,我们可以检查数据类型、解构复合数据、绑定变量等。Rust支持模式匹配的语法包括匹配守卫(match guard)、模式绑定(@)和模式切片等。模式匹配让我们的代码更加简洁、易读和健壮。

6. 错误处理

Rust的错误处理机制主要包括两种:可恢复错误(Result<T, E>)和不可恢复错误(panic!宏)。可恢复错误用于处理可能失败的运算,如文件操作、网络请求等;不可恢复错误用于处理无法恢复的场景,如程序逻辑错误。Rust还提供了?运算符,简化了错误处理的代码编写。

7. 并发编程

Rust提供了丰富的并发编程支持,包括线程、通道、互斥锁等。Rust的线程安全特性得益于所有权和借用机制,使得在多线程环境中共享数据变得简单。通道(Channel)是Rust中的一种并发数据结构,用于线程之间的消息传递。Rust还提供了跨线程共享数据的同步机制,如Arc和Mutex
总之,Rust是一门具有高性能、内存安全和并发性的编程语言。通过学习Rust,我掌握了所有权、借用、生命周期、类型系统、模式匹配、错误处理和并发编程等知识点。这些知识点不仅让我对Rust有了更深入的了解,还提高了我的编程水平。在未来的工作中,我会继续学习和实践Rust,为我国软件产业的发展贡献力量。

Rust一阶段总结

零、个人照片

随便放张生活照吧,很久之前拍的了,呵呵~时间过得真快

一、本次参赛情况概述

本人也是上届训练营参营成员,不过那时候是和一个水友组的队,基本只有我一个人在努力写题。想起上次训练营我啥也不会,也没看过《Rust语言程序设计》,抱着《Rust圣经》+ChatGPT硬啃,勉强过了一阶段的100题,后面由于二阶段实在是有点复杂,迫于学业和项目组项目压力,勉强做了两个就做不下去了。

这次拉了两个工作室成员,都是有一定工程基础的,有一位成员在此之前接触过Rust,所以这次一阶段至少还算轻松,不会了线下相互请教一下,最终也是慢悠悠地过了一阶段。当然这次总结我倒不打算主要讲Rust代码上的东西,哈哈,相比较于程序设计,我倒感觉思想上的收获更多。

二、rustlings任务完成心得

这次任务,我将之前的(多)线程、外部导入函数、裸指针、所有权与借用以及模式匹配更层次地理解了一遍。想起我上次都是靠GPT撑过来的,属实确实有点搞笑了,这里我总结一下如何跟着这个Rust训练营的学习方法:

2.1看官方文档

这里的官方有多个含义。

首先是训练营官方给出的环境搭建文档,跑软件不可避免要进行环境搭建,最简单也得学会用docker,学会了搭建最基础的环境,才能整式开始学习之旅。

然后是看《Rust程序设计》这本mdbook,一阶段很多知识点,其实可以从这本书找到答案,换句话说,这本书相当于rustlings的提示手册了,仔细钻研这本书,还是可以学到很多东西的,如果直接去看《Rust圣经》 对没有基础的同学来说还是容易劝退

最后就是看Rust语言的官方文档了,有中英双语版本,可以看到每个函数的具体解释,这里我推荐使用zeal这个软件安装Rust的文档进行查看,不需要联网,支持全局查找,还是很不错的

2.2看他人博客

虽然很多文档都有,但是大部分都是英文的,可惜我们一组3个成员英语都不太好,只能硬啃文档。另一种好的方法是去找别人学习源码的笔记,一遍写得好的笔记也是能传递很多知识的,我在仔细翻阅他们的笔记之后,加深了对所有权和一些陷阱的理解

2.3多动手实验

当然,理工科的东西还是以动手为主。我们由于本身有工程基础,于是乎就开始拉几台服务器自己装下环境,在ubuntu装,在windows装,在WSL装,在classroom装,都装一遍,写好通用的执行流程和坑点,加深对Rust的理解。

不过说实话,如果操作系统训练营要成为一门面向大众的训练营,以目前的文档详细程度来说,其实在文档上面下的功夫依旧不够,代入一个新手的视角来看,配置gitHub秘钥是陌生的,github进在线classroom运行时陌生的,git是陌生的,如果仅仅只有LInux基础还是很容易劝退,这就必须要个人有一点自主学习,热爱钻研的能力才能坚持下去,很多工程新手要完成这个阶段也得两三天。就我个人刚入门工程项目的时候,我自学git就很容易犯低级错误,或者进行不规范的操作,我觉得训练营至少要给出一遍基础操作,这样就能带动更广泛的学生参与进来。只要过了环境配置,后面通过一阶段那就只是坚持下去就能完成的事情了。

三、完成rustlings过程中遇到的困难

3.1语法不熟悉

其实环顾rustlings和《Rust语言程序设计》,这两者都没有重点讲Option是什么,Result是什么,unwarp()是什么,都需要自己去找额外的文档进行理解,很多需要的函数,不如trip(),insert(),get_mut(),as_mut(),as_ref()这些奇怪的函数,但是其实这些挺基础的,如果不会这些,不知道某些函数的返回值是什么类型,OPtion有什么用,其实是很难写下去的。鉴于以往学C++的经验,我自己重新学习了一下Rust的基本数据结构,以及基本数据结构的内置方法,还有一些通用方法和获取指针的方法,这些都是比较重要的。

3.2STL不会用

这次新增了一些算法题,颇有种使用C构建数据结构写算法的感觉,不过还好是填空的模式,对于没有掌握全部数据结构的我来说,还是能勉强接受的。致辞的算法题都是基于基本的容器进行操作的,比如bfs就是基于queue,算法里面使用deque,还有后面使用vec充当邻接表,还用到了hashMap当做node进行映射,不会使用容器做这些还是稍微有些困难的,当然,稍微学学容器方法还是可以写出来的

四、本次一阶段的收获

这次一阶段,我个人和另外的成员承担的项目任务更轻松了一点,拉了两个人来一起学习,还是蛮不错的

掌握了更多的学习途径和方法,从“正确的方向”巩固了Rust的语言基础,我现在感觉Rust+cargo越来越好用了,中途踩了几个小坑,每犯一次错误都能学到东西,嘿嘿~

五、自己找的学习资源汇总

权当分享啦~

5.1Rust 程序设计语言 - Rust 程序设计语言 中文版 (rustwiki.org)

5.2std - Rust (rustwiki.org)

5.3Rust 中文文档 | Rust 文档网 (rustwiki.org)

5.4关于本书 - Rust语言圣经(Rust Course)

5.5Rust入门第一课 - Rust入门秘籍 (junmajinlong.com)

5.6介绍 - Rust精选 (rustmagazine.github.io)

5.7简介 - 通过例子学 Rust 中文版 (rustwiki.org)

呼~ 第一阶段就这样结束了呀!

自打去年从群友们那里了解到这个训练营之后就一直在关注了,
因为我对操作系统本身就很感兴趣,
加上又是使用 Rust 语言还能有一群小伙伴一起努力何尝不是一个很好的学习机会。
其实去年秋季也有报名过一次,惭愧的是因为各种原因第一阶段都没写完 uwu

对于 Rust 这么个频繁被推荐的语言,难免是有些好奇的,
常常是拿出 《Rust 权威指南》然后翻过前几章与别的语言相差不大的那些部分后打算狠狠一顿学习,
但又是惭愧的是每次品鉴 “生命周期”、“所有权”、“动态分配 Trait” 等几个词语后便急忙把书塞回它该在的地方了。
可恶!怎么这么点字就是看不懂了 ——

于是今年刚报名完春季的训练营后便暗自地赌气:我要一晚上做完第一阶段

(是的,真的第一天晚上就做完了,鉴定为太能熬夜了)

除了 Rustlings 外今年还添加了一部分数据结构和算法的内容,包括常见的队列、链表、二叉树和排序等,
而且比较有意思的是因为 Rust 对安全性要求很严苛,找出一种写法不使用 unsafe 也是一种很不错的挑战。

三分时间写七分时间对付编译器那种(雾)

后续的三周就比较空闲了,我终于找到了一个机会和理由把《Rust 权威指南》看完了,
后来还发现一本《Effective Rust》类似是《Effective Java》或是 C/C++ 版本一样,通过一些案例说明什么写法是好的什么写法不太完美。
期间留下一些小笔记:https://blog.hanbings.io/posts/effective-rust/

总的来说,还是很感谢社区以一个这样的形式提供了一个这么好的学习机会,希望后续的学习还能够坚持下去吧!
那么… 第二阶段见!

前言

2022年在和同事聊天的时候了解到了Rust,在他的推荐下“投资未来”,学习了Rust这门语言。前期确实困难重重,Rust的
学习曲线确实比较陡峭,在三本Rust著作(《Rust权威指南》,《Rust实战》,《Rust程序设计》)和极客时间《陈天 · Rust编程第一课》的帮助下算是成功入门。

2023年参加了“第三界中国Rust开发者大会”,收益破丰,也是在这里第一次了解到“操作系统训练营”,今年在公众号“Rust语言中文社区”
了解到2024训练营要开办了,果断报名。

希望通过训练营的学习与实践能进一步夯实Rust语言功底,掌握操作系统知识,拓展知识面。

第一阶段总结

第一阶段主要是Rust的基础学习部分,110道题目巩固了不少基础语法知识。让我感觉最有收获的是后面的
10道算法题,之前有用Rust刷过一些LeetCode,但用Rust来实现栈,堆,队列等经典数据结构却是从没做过的,这一次有了了解。
除了实现数据结构外,这次做题也第一次编写“有意义的”unsafe代码,它终于不再那么神秘莫测了。

RISC-V

参加训练营是第一次接触RISC-V,目前正在学习《RISC-V-Reader》。RISC-V有一个很鲜明的特点是模块化,这似乎是技术发展的未来趋势,各种现代编程语言都
在使自己模块化,如Java,生活中常用的设备也在模块化,如笔记本电脑,手机,甚至我这个月刚买的小米鱼缸,RISC-V走在了ISA模块化的前沿。

下一步

目前打算在第二阶段开始前看完《RISC-V-Reader》,之后再补充一些操作系统的知识,为第二阶段的学习做好准备。

开端

从同学听到有关这个开源夏令营的事情,一方面对rust这种新兴语言颇为感兴趣,另一方面也正巧学习计算机系统知识,认识到计算机系统的精妙,也希望借此机会提高自己对计算机系统的理解,获得一定的开源经验。

链接

主要的笔记都记录在notion中,主要包含我rustlings过程中的思考和体会,记录比较精简。
https://ash-chair-1e2.notion.site/193e1434faf44e5587e71865fc9614af?v=6e2890c3bd084a77b864410b009d9706&pvs=4

第一阶段总结

这一阶段主要是熟悉rust语法以及相关知识。在我的学习中看来,rust主要有以下几个难点:

  1. 控制权转换。
    • rust中,move是默认语义,而浅拷贝(在rust中被称为引用)成为了次要语义,这使得程序需要不断地考虑生命周期
  2. 引用的简写
    • rust中让我最不能够理解的是引用的自动解引用功能,我认为一个强类型语言可以用更加明了的方式进行引用和非引用的区分。当然这只是我的浅薄观点,因为引用和非引用的自动转换实在让我伤透脑筋。
  3. 生命周期
    • 实际上rust中存在对生命周期非常精准的控制,然而受限于我的学习速度,还没有对生命周期参数和控制有更深的了解。
  4. 大量的现代特性
    • 在学习rust的过程中,我体会到了很多“旧语言”没有的特性,例如函数式编程、模板约束、宏的元编程等特性。这不禁让我想起了学习现代C++的某些特性(但是根本没有实际使用过)

第二阶段

接下来,主要就是学习riscv指令集,同时准备把更多时间花在系统课程上,配合CSAPP学习一个操作系统的基础实现。

学习Rust有一段时间了,做rustlings中途没有写blog,正好总结一下作为初学者对Rust的一些关注点和总结。

没写完,就先这样吧(逃)

todo!();

Rust基本语法

变量

Rust变量声明使用let,类型放在变量名后面。例如:

1
let x: i32 = 114514;

Rust也能自动推断类型:

1
2
let i = 114514;
let s = "string".to_string();

i被自动推断为i32s被自动推断为String

有些情况Rust也不能自动推断类型,比如:

1
let v = vec![];

报错信息如下:

1
2
3
4
5
6
7
8
9
10
error[E0282]: type annotations needed for `Vec<_>`
--> exercises/variables/variables1.rs:10:9
|
10 | let v = vec![];
| ^ ------ type must be known at this point
|
help: consider giving `v` an explicit type, where the placeholders `_` are specified
|
10 | let v: Vec<_> = vec![];
| ++++++++

这是因为Rust是一门静态类型语言在编译期必须得知变量类型的大小。

函数声明

声明方式大致如下。

1
2
3
fn func(a: i32, b: i32) -> i32 {
a + b
}

…很多内容在其他语言都有类似的概念,只是语法稍有不同,因为懒惰不再赘述

Rust的特色

作为一门年轻的语言,Rust整合了许多其他语言的优势,比如C/C++的底层系统编程能力、Ruby 的包管理器Bundler (cargo)等等。而除了严格的编译期检查、所有权和生命周期机制实现的内存安全,Rust也有许多其他大大小小的特色和亮点,比如:

组合优于继承

表达式

模式匹配

闭包

使用Option来表达可能为空的值

使用Result来处理异常

各种智能指针

使用RefCell实现内部可变性

Rust与数据结构和算法

学Rust当然要从链表写起!
==学Rust千万不要从链表写起!==

Rust如何实现链表?

按照C/C++的一贯做法,我们可能会写出:

1
2
3
4
struct node {
val: i32,
next: Box<node>,
}

然而实际用起来,会发现你用不起来

1
2
3
4
5
6
let n = node {
val: 114514,
next: Box::new(node {

})
}

问题就在于Box里必须要有东西,即它任何时候必须指向一个有效的元素!别说链表末尾节点如何实现,我们甚至无法完成头节点(任何节点)这样一个递归定义的形式。

于是我们想到使用Option来表示可能为空的值,从而能够定义单个节点。

1
2
3
4
struct node {
val: i32,
next: Option<Box<node>>,
}

面向rCore的Rust

为了完成rCore,还需要深入了解Rust的哪些?

unsafe

外部接口

Rust编译和链接

Rust项目结构

另外推荐:《Rust死灵书》

始于rust

在参加训练营之前,我学rust有大概一年的时间了。rust是一门让我惊叹的语言,同时我也学到了很多。第一次完整阅读一本英文书正是官方的the book,它极大的提高我对英语的兴趣以及阅读能力。在rust之前,我学过c、c++、java、python以及go,但是毫无疑问我现在是rustacean,因为rust的设计哲学简直太赞了,其中特别是rust对option和错误的优雅处理。
学完rust后我就经常逛rust中文网,刚好了解到开源操作系统训练营,由此开始了我的开源操作系统之旅。

第一阶段总结

前100题主要是熟悉rust语法,其实这次我是第二次参加了,因此前100题对我来说没什么压力。后十题是算法题,涉及链表、二叉树、图等。学过rust的同学知道,在rust中处理自引用的数据结构相对其它语言会难上许多,不过真正了解过Box、NonNull等之后会感觉还好。这次二刷rustlings我又深入看了下标准库的Box、NonNull等结构,收获颇丰!