0%

1. 引言

本人参加2024春夏季开源操作系统训练营,主要基于对Rust编程语言的浓厚兴趣以及从事操作系统相关工作的背景。训练营的第一阶段聚焦Rust语言学习、习题实践以及算法研究,旨在深化对Rust与操作系统的理解,提升实际工作能力。经过这一阶段的学习,我收获颇丰,现对本次学习进行总结。

2. Rust语言的学习:

  1. 通过对 训练营中的 rust资源学习 比如 带有测验的文档 对rust语言的设计 拥有更深入的理解, 明白 rust语法以及规则上的设计道理,而非仅仅通过编译器的编译。
  2. 通过 项目的事件项目 rcore的rustling 对 rust语法规则更加熟练的掌握, 对于 unsafe 以及FFI 的使用有一定的掌握。
  3. 通过 训练营 中 徐老师的 直播视频讲解,对 rust 的生态,以及 Future,类型 变换(协变、逆变、不变) 以及一些其他的 冷门 rust知识 有更深入的理解。(感谢老师的付出

3. 总结与展望

总体来讲, 这些天的rust项目实践带来了不少的收获。本人自身对于OS也比较好奇和一定的知识储备, 希望能够在接下来的课程中通过rcore的项目实践,能够带来 更多对于rust以及OS的 深入理解。

第一阶段总结报告

我大概在一年前知道了开源操作系统训练营,但是因为种种原因没有参加。在今年4月的时候我看到2024春训练营,正好有时间就赶紧报名上车了。

学到的东西

虽然我学习过rust,但是在做rustlings时我还是学到很多东西。

  • Rust Docs
    这次解题的时候因为很多东西都需要自己去了解,这个时候我们就需要去看看相关rust文档,尤其是test7和test8中的那个build.rs。
  • Iterator
    rust的迭代器实在太强了,过去只是简单用一下。在这次rustling的拷打下,我边做题边翻rust的Iterator文档,学到了很多新的Method,多个Method组合在一起解题太舒服了。
  • Heap
    因为我本科没学过数据结构,所以做到第109题的时候发现自己竟然连堆这个数据结构都不知道,然后赶紧去学习Heap。
  • FFI
    我被test9这道题给卡了很久,看文档也不懂,一直对提示的2个attribute的用法不太明白,最后看了一篇关于这个问题的rust社区讨论才明白。
  • Codespace
    最开始我只是想要在上水课的时候用平板做一下题,然后就选择体验一下codespace。我使用了一下后发现体验还不错,就选择在codespace上做完了rustlings,这篇blog也是在codespace上写的。
  • Match Ref Mut
    我在做一道题的题的时候遇到了模式匹配的可变引用问题,被它卡了很久,最后看了下rust blogrust by example和编译器的帮助下解决了它。

总结

第一阶段学到了不少东西,希望自己后面能挺过第二阶段。顺便吐槽一下,后面10道算法题的测试用例有点弱和少,希望后面可以加强一下。

一阶段总结

没有太多可说,rustlings 中规中矩,最后新增的十道算法题有一种复古的感觉。期待二阶段的内容。

想法 rustlings, kotlin koans and others

类似这样的一连串渐进的练习组成的交互式教程,感觉没有直接看书那么有意思,有时甚至都懒得看代码就改完了。
速成也没有 learn x in y minutes 快。也许比较交互,减少代码恶意 :P

想法 stage-2: rcore os lab

提高 OS & RISC-V 知识水平。

  白熊的专业是微电子科学与工程,并不是传统计算机大类中的专业,但是看到朋友转发的操作系统训练营宣传后,想借这个机会熟悉一些关于操作系统的内容,增强自己对硬件驱动、指令集等(尤其是RISC-V)的了解。由于之前没有系统地学过任何计算机方面的知识,而且还是个freshman,基础可以说是相当薄弱,在第一阶段学习Rust的过程中,我也生出了不少傻头傻脑的见解,甚至被贺兰神评价“少见多怪”。不过经过一段时间的学习,我最终完成了第一阶段rustlings的所有题目。本文就写我初见Rust的一些想法咯~

对Rust的认知变化(做rustlings有感)

  在学习Rust之前,飞飞神有跟我普及过Rust,说它很安全,但写起来很麻烦(举了Rust变量所有权的例子)。当时我没太理解,但不明觉厉,很长一段时间里我认为Rust安全且牛X,是某种高贵而神秘(雾)的语言。

  参加训练营刚接触Rust半小时时,因为看到了很多熟悉的语法,我心里对Rust的期望似乎有所降低,觉得Rust不过是语法与其他语言略微不同……直到我看到了所有权、借用的概念,才真正感觉到这语言非同一般。可是rustlings中所有权一章的题目都挺简单的,没有为难人,这给了我一种“我已经完全了解所有权”的错觉……事实证明并非如此,在后续的题目中,随着代码复杂度的上升,经常会出现把一通报错改成另一通报错的情况,不过正是这些拷打,让我对这些新概念的理解慢慢扎实起来。

  rustlings中间做得还蛮快的,不过感觉我自己有点囫囵吞枣,有一种知识从光滑的大脑溜过的感觉……直到多线程那一块,我彻底卡住了,大脑宕机……后来想了想原因有二:一是对前面知识点根本没有理解透彻;二是我完全没有接触过多线程方面的知识(以前写代码都是傻乎乎单个过程)。最让我崩溃的是支持多线程的可变借用的题,第一次做的时候调来调去搞不明白,挺打击自信的……后来把Rust学习扔在一边,两周后重新拾起来,居然很快解决了,看来学习真的需要“沉淀”的过程。

  接着便没什么困难,直接杀完了基础的100题。算法题我感觉不算很难,毕竟都是很简单的数据结构。不过我认为我的答案不太简洁,可能(一定)包含很多没必要的操作(传值),或有优化的多的写法。归根到底还是自己对Rust的变量体系不熟悉,希望在日后的学习中,慢慢强化这方面,有些问题还是得交给时间(笑)。

一些展望

  正如开头所说,我基础很薄弱,不指望能完成整个训练营,所以便怀着“主打学习”的心态。希望在第二阶段中我能建立对操作系统的认知框架,并尝试将其与我自己的专业知识结合——说不定暑假可以亲手用数字电路实现处理器,跑操作系统,想一想都觉得很酷(前提是我得会)。

2024春季开源操作系统训练营第一阶段总结

作为一个非计算机科班的自动化人,对于计算机的学习有着很高的热情,在好友的推荐下,我了解到了开源操作系统训练营。刚好最近想要做一些相关的lab,就借此良机,加入到这个大的训练营家庭中和大家一起学习。在以前的学习中,常用C/C++,这次新学习了Rust语言,编程习惯还是有些不同(悲),要花大功夫去掌握难点。

学习过程:

  • 我主要使用了《Rust 程序设计语言》官方文档作为学习指南,并结合rustling进行知识点的学习和巩固。
  • 开始的基础语法较容易,很快就做完了,但是到后面的tests和algorithm部分,难度增大了,花费了不少时间才完成题目(难难难)。
  • 坚持就是胜利,每天都感觉有进步。
  • 主要难点部分在所有权系统、模式匹配、trait和生命周期,还需要多加联系。

总结与展望:

通过这20天的学习,我对Rust语言有了更深入的了解,也掌握了一些基本的编程技能。期待进入第二阶段的学习了。加油干小伙子!

Rust语法学习

这里将学习Rust中感到困惑的一些Rust语法进行整理

变量隐藏

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
using namespace std;

int main() {
int x = 5;
x = x + 1;
{
int x = x * 2;
printf("in for : %d\n", x);
}
printf("out of for : %d\n", x);
}

这段代码的输出结果是

1
2
in for : 0
out of for : 6

在 C++ 中,当你在 for 循环内部声明一个新的变量 x 并试图初始化它为 x * 2 时,这里的 x 实际上是指向新声明的 x,而不是外部作用域的 x。因为新声明的 x 在这个时候还没有被初始化,所以 x * 2 的结果是未定义的,但在大多数情况下,它会被初始化为 0。

这是因为在 C++ 中,新的变量 x 的声明和初始化是在同一条语句中完成的,所以在 x 的值被计算(即 x * 2)时,新的 x 已经遮蔽了外部作用域的 x

1
2
3
4
5
6
7
8
9
fn main() {
let x = 5;
let x = x + 1;
{
let x = x * 2;
println!("inner {x}");
}
println!("outter {x}");
}

而rust中的结果是

1
2
inner 12
outter 6

这段代码中的 x 变量在不同的作用域中有不同的值。在 Rust 中,可以在一个作用域中重新声明一个与外部作用域同名的变量,这被称为变量遮蔽(shadowing)。

首先,x 被初始化为 5。然后,x 被重新声明并赋值为 x + 1,所以 x 的值变为 6。

然后,进入一个新的作用域(由 {} 定义)。在这个作用域中,x 被重新声明并赋值为 x * 2,所以在这个作用域中,x 的值变为 12。这个值在 println!("inner {x}"); 语句中被打印出来。

当离开这个作用域时,我们回到了外部作用域,x 的值再次变为 6。这个值在 println!("outter {x}"); 语句中被打印出来。

字符串与所有权

结构体元组

成员相同但名称不同的元组不是同一种元组,不能相互赋值

生命周期的3个规则

生命周期约束

'a : 'b 表示 a >= b

子类型的生命周期

SubSuper 的子类型, Sub 的生命周期要包含 Super 的范围,有可能更大

目前Rust生命周期的子类型关系对于泛型存在三种映射

  • 如果 TU 的一个子类型意味着 F<T>F<U> 的一个子类型(即子类型化“通过(passes through)”),则 F<T>T 上是协变的(covariant)_。
  • 如果 UT 的一个子类型意味着 F<U>F<T> 的一个子类型,则 F<T>T 上是_逆变的(contravariant)_。
  • 其他情况下(即不能由参数类型的子类型化关系推导出此泛型的型变关系),F<T>T 上是的_不变的(invariant)_。

引用的生命周期

引用的生命周期从借用处开始,一直到最后一次使用的地方

再引用(ReBorrow), 将指针解引用后再引用的行为,如let ptr2 : Point = &*ptr1;

const泛型

无界生命周期

闭包

闭包中如果未声明参数类型那么一定要使用,否则编译器无法判断是什么类型

闭包根据参数在函数体内如何使用判断捕获参数的类型,可变还是不可变

使用move关键字强制获取所有权

智能指针

表现类似指针,同时拥有额外的元数据和功能,如String在内存中的分布

Box<T>

  • 当有一个在编译时未知大小的类型,而又想要在需要确切大小的上下文中使用这个类型值的时候
  • 当有大量数据并希望在确保数据不被拷贝的情况下转移所有权的时候
  • 当希望拥有一个值并只关心它的类型是否实现了特定trit而不是其具体类型的时候

    使用Box<T>创建递归类型

示例

1
2
3
4
5
6
enum List {
Cons(i32, List),
Nil,
}

let list = List::Cons(1, List::Cons(2, List::Cons(3, List::Nil)));

实现Deref以及函数和方法的隐式转换

通过std::mem::drop提早丢弃值

Rc<T>引用计数

Rc::new 创建

Rc::clone(&a),获取只读所有权

调用Rc::strong_count获取计数

RefCell<T>和内部可变性

对于引用Box<T>借用规则不可变性作用于编译时,对于RefCell<T>不可变性作用于运行时,如果违反则panic

原子计数引用Arc<T>

多线程中的Rc<T>

第一阶段总结

感谢活动主办方提供的宝贵平台和资源!

希望自己至少能坚持做完二阶段。

RUST

学习资料:

rustlings 110题 https://github.com/LearningOS/rust-rustlings-2024-spring-zhouyecs(已完成)

rust语言圣经 https://course.rs

rust练习实践 https://practice-zh.course.rs/

rust by example https://doc.rust-lang.org/rust-by-example/

半小时学习rust https://fasterthanli.me/articles/a-half-hour-to-learn-rust(已完成)

rust algorithm club https://rust-algo.club/(已完成)

《rust实战》https://www.amazon.com/Rust-Action-TS-McNamara/dp/1617294551

(rust资料太多,慢慢学……)

RISC-V

之前学习过《计算机组成与设计(RISC-V版)》,所以这次只是简单地看了一下PPT for RISC-V特权指令级架构,打算后面有时间学习RISC-V手册:一本开源指令集的指南Berkeley CS61C: Great Ideas in Computer Architecture (Machine Structures)

rustlings 难点记录

rustlings 110题 https://github.com/LearningOS/rust-rustlings-2024-spring-zhouyecs

参考资料

- The Book - The most comprehensive resource for learning Rust, but a bit theoretical sometimes. You will be using this along with Rustlings!

- Rust By Example - Learn Rust by solving little exercises! It’s almost like rustlings, but online

做题的时候忘记边做边记录了,所以选了些难点记下来。

引用

这里和C/C++类似,引用使用 & ,解引用使用 *

1
2
3
4
5
6
7
8
9
10
11
fn main() {
let needle = 42;
let haystack = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862];

for reference in haystack.iter() {
let item = *reference;
if item == needle {
println!("{}", item); // 42
}
}
}

字符串

Rust中,strString是两种不同的数据类型,特别容易搞混,str是字符串切片类型,是一个不可变引用,而String是字符串类型,是一个可变的字符串。

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
fn main() {
// 使用字符串字面量创建一个str类型的字符串切片
let str_slice = "Hello, World!";
println!("str_slice: {}", str_slice);
// 尝试修改str_slice会发生报错

// 使用String结构体创建一个可变的字符串
let mut string = String::from("Hello");
println!("string: {}", string);

// 修改String类型的字符串
string.push_str(", World!");
println!("string: {}", string);

// String -> &str
let s1 = String::from("PKU");

let s2 = &s1[..];
let s3 = s1.as_str();

// &str -> String
let s4 = "THU";

let s5 = s4.to_string();
let s6 = String::from(s4);
let s7 = s4.to_owned();
}

还有更多就没写了,还是得多练练。

训练营第一阶段主要是通过上课以及Rustlings练习的方式学习Rust语言。Rust语言在学校的时候已经学过一遍了所以做起来还算轻松。

Rust语言学习心得

在学习Rust语言的过程中,我深深地感受到了这门语言的独特之处以及学习的挑战。通过完成第一阶段的Rustlings练习和复习Rust语法知识,我收获了许多宝贵的经验和见解。

Rustlings

Rustlings是学习Rust非常好的资料。

通过解决各种练习题,我不仅熟悉了Rust语言的基本语法,还学会了如何处理各种常见的编程问题。尤其是在处理字符串和迭代器等常见操作时,我学会了如何巧妙地利用Rust语言特性来简化代码,提高效率。

第一遍做的时候以为全过,过了n久才发现fail了三道,飞速赶工修好了。。。

另外,Copilot和ChatGPT真的非常好用。

未来期望

希望能够入门Rust-for-linux,真正在各种现实项目中用起来Rust。

第一阶段总结

回顾

这是第二次参加rcore训练营了,上一次的时候是2023秋季的时候,那时候还没有学过rust,也不知道risc-v。而是在学过操作系统课后,想要找一个操作系统实验来做,锻炼自己。因为自己平时很喜欢c++,而各种地方都在不断拿Rust和C++对比,因而开始去接触Rust,也因此,正巧碰上了2023秋季rcore训练营的开启。去年时间很短,个人基础也很差,所以学得很费劲,磕磕绊绊才把第二阶段过了。刚到第三阶段,碰上了期末周,导致没有继续持续下去,很是遗憾。所以又在等啊等啊,2024年春季的rcore终于开始了……。

rustling

由于上次做过,所以本次的前一百道题做得很顺利,花费的时间很少。直到今年多出来的10道算法题,其实思想也是很简单,就是用Rust来写很让我难受。尤其第一题的链表,让我实在……,用c++写得挺感觉很简洁或者轻松。但rust写起来……拖着最后还是不得不写完了。

Rust

Rust算是我学过的一种蛮特别的语言。开始C->C++->Java/python。我感觉基础语法什么的基本都差不多。但是Rust确实是给我的感觉不太一样,风格不一样。但学的时候,却是在不断对比C++来学习,学起来确是不断加深对两门语言的印象。总之Rust促使C++更多思考安全!,但对Rust也越来越喜欢了。总之,两个我都要。

第二阶段好好搞!!!

Rustlings 学习感悟

不得不说,Rust对于我这种只会C/C++的语言的人来说还是很有一定难度的,这种难度来自于对于函数式编程的不熟悉。但一旦熟悉后就感觉到了函数式编程的便捷,特别是迭代器的处理。同时这也增加了一些压力,相较于啥都自己手写的C/C++,Rust等函数编程语言的重点则是熟悉各种各样的函数方法,有时候自己冥思苦想几天的代码,一个简单的函数就能解决,这种经历还是很难受的。

Rust语言除去函数编程以及一些语法糖之外,令人啧啧称道的就是他的安全机制了。确实,初次接触Rust感觉十分惊艳,觉得取代C/C++只是时间问题。但做过Rustlings后,感觉到可能这还是存在一些距离。一方面对于程序员要求太高了,难度感觉比C/C++高出了很多,另一方面尽管尽力屏蔽了底层,但却不得不使用一些unsafe的代码块实现底层操作,导致有点emmm怪怪的。

难度方面,我感觉Rustlings中的algorithm系列题目可以展现出Rust的“刁钻之处”,特别是对泛型T的处理。由于泛型T既可能有Copy也有可能有Clone,这导致很多常规的赋值方法并不能使用,在老师的讲解中我了解到了

1
2
let mut k = T::default();
std::mem::swap(&mut k, &mut self.data[self.top]);

这种写法,但实际使用中还是存在很多限制。不过经过思考和练习,发现很多赋值是可以优化的,特别是在使用相对应的数据结构的方法。感觉这其实有点像编译器强制程序员思考优化代码(被鞭策的感觉。

底层操作方面,则主要还是指针的使用,不得不说,链表之类的使用指针写代码是真的快。不过网上关于这个争议还是蛮多的,我有一段实现safe的双向链表代码,可惜这里太小了粘不下(笑

Rustlings 感觉练习还是蛮不错的,对于我这种0基础的学生来说,三四天看完b站课程后刷完成就感还是蛮强的(虽然看了不少题解,特别是经过最后algorithm部分的练习,感觉自己算是初步入门了Rust

RCore 学习感悟

作为一个只会408操作系统的电子学生,很早之前就想从代码阶段了解操作系统的构成,很感谢训练营能够给我这次机会。

但不得不说,使用Rust语言实现的RCore对我这种只会C语言的难度有点大,各种各样的闭包、智能指针让我看得经常找不到北。坦白来说,就算经过RCore的学习,RCore的很多细节我仍然不是很熟悉,只能说大概框架是有的,这一方面是因为操作系统的本身难度,作为一个之前没有太多接触操作系统的学术,这样一个包含汇编、C语言、Rust的大型工程实在是令人压力山大,另一方面则是Rust本身的难度,这语言是有点抽象的(o(╥﹏╥)o),本以为经过Rustlings学习能够大展拳脚,结果发现自己只是入门的阶段,经常忘记用闭包,函数式编程的思想,常常都是C语言的编程逻辑(还是自己太菜了)。

不过,经过RCore的学习我还是收获颇丰,不仅精进了我的Rust技术,更是极大地扩充了我的操作系统知识,原先只能死记的知识点,现在又有了不一样的理解,比如说管道的实现、内核态和用户态的地址,另外也学习到的书本上很少涉及的知识,比如说用户态空间与内核态空间分离(RCore称之为双页表),SV39多级页表机制等等。

经过RCore学习也能感受到自己的不足,特别是汇编部分,不得不说RCore的汇编涉及太巧妙了,经常是读下来感觉耳目一新,醍醐灌顶。希望以后有机会还能参加编译器的训练营。