0%

第一阶段总结

第一次接触 Rust,之前使用的一直是 C/C++、Python,对于 Rust 基础语法来说掌握比较快速,但是遇到一些进阶的方法就开始有些困难了,感觉很大一部分问题还是因为 coding 的太少,光从 110 到训练题目来看,代码量还是不够多,容易导致语法学习了又忘记了,希望能够在第二阶段的学习当中,进一步学习 Rust,同时掌握一些 Rust 的最佳时间。

以前一直听说 Rust,都说写 Rust 是与编译器斗智斗勇,在体验过后,发现确实如此,一直致力于如何写出让编译器开心的代码,Rust 很有意思,OS 也很有意思,希望在接下来的学习中能够学习更多的知识

第一阶段完结!!!!

总结

花了一天的时间,通过 rustlings 的 110 道题目重新过了一遍 rust 相关的语法和细节,帮助我重新学习巩固了很多之前没有掌握的细节。特别是智能指针相关的部分,之前对于 Arc,Box,Cow 之类的掌握的都不是很细节。

再感概一句,rust 的编译器真是太好用了,很多语法上的问题编译器都可以给你正确的提示,如果再配合上 CoPilot 简直就是学习利器,大大提升了学习效率。

这次知道训练营的时间太迟了,导致我没有能从头开始跟着上课,想来是错过了很多学习的机会和细节,希望后面第二阶段可以全程 follow,完成所有的任务。

总结

学习前的初印象

其实在参加此次训练营之前,我已经浅浅接触了一下Rust;起初是因为旁人的安利,我开始简单了解Rust,发现其所有权机制似乎能解答很久以前我关于对象内存释放解决方案的一个不成熟的想法;随后又用Rust写了一个很简单的小工具,又发现它的奇妙之处在于:一旦通过了编译器的拷打之后,程序再拿去运行就几乎不会再报错了。在我看来,编码期早解决问题,要比运行期晚解决问题好多了!这就是训练营开始前,Rust给我的两点初印象。

学习后的印象和比较

在开始学习Rustlings后,我才发现对于Rust的了解我还是太少了——Rustlings的习题设计相当全面、有趣,在做题实践中学习要比只对着文档阅读生动得多;如果把写代码当做是添加一系列描述来使得程序不断具体化、直到能够实实在在运行起来、交付价值的过程,那么Rust就提供了相当丰富的机制,去极其精细地描述程序。尽管贴标签难免是一种以偏概全的行为,但我还是非常喜欢用一些词语给接触过的编程语言贴标签:C语言是经典悠远,Python是简练干净,Go是轻快简陋,Java是丰富啰嗦,C#是优雅如诗(这些全是我的刻板印象!但也是我真实的内心体验),那么Rust就是精细严谨。

Rustlings中一些地方的回顾

Rustlings中,有的语法点虽然之前已经略有耳闻,比如所有权机制,但运用起来还是时常碰壁,对这部分后续可能还是需要加深理解;有的语法点之前在其他语言里也有接触过,比如Optional;有的语法点给我耳目一新的感觉,比如错误处理机制,感觉写法上就相当漂亮。

展望

各大IT论坛上经久不息的争论之一大概就是“谁(PHP)是世界上最好的语言?”,曾经我也很着迷于这个问题;现在我更想搞清楚每种语言的最适合的场景;在学习了Rust之后,我想将来要在核心或是底层模块上多多锤炼自己的Rust水平,恰好这次的rCore实现就是一个非常好的训练机会~

总结

我作为常年 C++ 选手,第一次体验 Rust,说几个令我印象深刻的点。

模块与 cargo

cargo 无疑是 Rust 相比 C++ 最闪耀的点之一,C++ 既不便于源码分发又难以二进制分发的特点,令几乎所有 C++ 程序员苦不堪言。Rust 的模块机制消除了 C++ 的头文件与源文件的区别,使得模块的划分更加清晰,同时 cargo 的依赖管理使得项目的构建更加简单。

当然,它也付出了对应的代价,比如编译不再是无状态的,不方便类似于 ccache 的工具做缓存,不方便做分布式编译。

enum

熟悉 C++ 的程序员对构造 Sum type 并不陌生。Rust 直接引入了 enum 关键字,使得 Sum type 的定义更加简洁,同时也引入了 match 关键字,使得对 Sum type 的处理更加优雅。

Ownership

Rust 的所有权机制是 Rust 最大的特色之一,也是最令人头疼的地方。Rust 的所有权机制使得内存安全问题在编译期就能被发现,但也使得程序员需要花费更多的精力去思考内存的所有权问题。

无状态的 struct

Rust 有一个我非常欣赏的地方,就是 Rust 的结构体不需要一个构造函数。构造函数和看似是一个非常便利的特征,一个对象创建时我们就能保证它处于一个正确状态,实际上却令心智模型变得更为复杂。程序员假设一个对象总是处于正确的状态,总是具有正确的生命周期,这使得容器类的设计变得更加困难。

背景

作为一名非计算机相关专业的学生,我写过的代码并不多,编程语言也仅了解C/C++,Python。参加这个训练营是因为有读研转码的想法,希望提前积攒些项目经验。浏览完该训练营的大致内容后觉得对于Rust零基础操作系统零基础的我来说算是蛮困难的一个挑战,希望自己能坚持到最后。

语言神,启动!

第一阶段总结

从4月6号开始学习Rust,到4月22号完成Rustlings共计17天大致学习了Rust的一些语法和特点。学习过程中最大的感受就是安全,安全,还是安全,相比于C/C++,Rust施加了太多的限制以保证安全,初次学习比较难以适应,但好在编译器的提示功能非常强大,帮助我解决了很多困难。目前个人觉得Rust中最难的部分就在生命周期,学起来非常打脑壳。

我主要通过读《Programming Rust,Second Edition》这本书来学习,主要学习了Rustlings涉及到的基本数据类型,所有权与移动,引用,表达式,错误处理,Crate与模块,结构体,枚举与模式等章节,而并发,异步编程这些章节暂时还未涉足。

完成Rustlings的过程中,前100题有编译器的帮忙都还较顺利,后10题涉及到数据结构与算法我还得先去学学前置知识,再加上整体也比前面复杂了不少,最后也是花了好几天才完成。

总之第一阶段算是坚持了下来,收获也蛮大的,希望第二阶段再接再厉。

Rust学习感悟

整体来讲,学习Rust的语法和性质是一个较为享受的过程。对于一个长期编写C++程序的人而言,在运行时出现内存泄漏、多线程死锁的问题并调试是十分棘手的,为了保证写出健壮的程序,程序员通常会有很大的心智负担,而Rust语法从编译层面就很大程度上保障了安全性,使通过编译的程序能在运行时也不出岔子的可能性大大增加。此外,Rust拥有很好的文档帮助新手入门,拥有完善的工具链,能够胜任各方面的开发。Rust的编译器十分强大,能够在所有权,生命周期等方面及早扼杀bug。

exercise 心路历程

我更倾向于在练习中学习语法,所以我在简单阅读了Rust圣经后,就开始进行rustlings的exercise了。基本上每个题,在查阅了相应语法后,都能顺利解决。最后10道编程题,考察了一些基础数据结构在Rust语言上的实现,由于对数据结构本身比较熟练,所以这些算法题更是考察对Rust语言本身的理解。

总结

rustlings是个很好的Rust学习项目,很适合rCore Lab入门Rust使用。Rustlings的练习顺利完成了,希望后期也能继续跟进。

在参与了2024年春夏季开源操作系统训练营的第一阶段后,我对Rust语言和操作系统的基础知识有了更深入的理解和实践。以下是我在这一阶段学习中的一些关键点和遇到的挑战。

Rust语法

所有权和生命周期

  • 所有权系统:Rust的所有权系统是其最核心的特性之一。它通过编译时的严格检查,确保了内存安全,避免了内存泄漏和悬挂指针的问题。所有权的转移和借用机制,让我对资源管理有了全新的认识。
  • 生命周期标注:生命周期的概念在Rust中至关重要,它帮助编译器理解引用的生命周期。在实际编程中,合理地标注生命周期对于避免悬垂引用非常关键。

语法问题

  • 在处理Option类型时,我曾错误地尝试解引用一个None值,这在Rust中是不允许的,因为它会导致运行时的panic

以下是我在 Rust 中编写的一个简单示例,演示了如何使用 Rust 进行错误处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
let result: Result<i32, &str> = divide(10, 0);
match result {
Ok(value) => println!("Result: {}", value),
Err(err_msg) => println!("Error: {}", err_msg),
}
}

fn divide(x: i32, y: i32) -> Result<i32, &str> {
if y == 0 {
Err("Cannot divide by zero")
} else {
Ok(x / y)
}
}

我定义了一个 divide 函数来执行整数的除法运算,并返回一个 Result 类型,表示运算结果或错误信息。在 main 函数中,我们调用 divide 函数并使用 match 表达式来处理返回的结果,打印出相应的信息。


这学期学操作系统让我发现了蒋炎岩老师的操作系统,又偶然了解到这次的OS训练营,又是rust,刚好就报名参加,第一阶段学习了rust,让我收获颇多,希望在第二阶段能学到更多的知识(希望能完成)。

​ 一转眼110道题目已经结束,100道语法练习和10道算法题下来让我受益匪浅。对于此前只有一些c语言和python语言基础的我来说,难度比较大,很多概念还是理解不清楚,算法也是临时学的,可谓非常艰难。不过对rust的学习对我的编程思维很有启发,也是我第一次直接接触到并发和所有权的概念。

​ 此前编程单纯考虑能跑就行,但实际上是不够的,作为信息安全专业的人这几年写代码从不考虑安全实在是惭愧,所幸在学生时期接触到了rust,不至于在未来项目出现一些令人痛苦的问题后惊觉对底层知识的忽视。随着学习的深入,越发理解底层知识对编程的重要性,当然这也是我参加2024oscamp的原因。不罗嗦了,那么作为简单的记录,先总结一下吧!

:Rust 中有两种字符串类型:String&str

String 被存储为由字节组成的 vector(Vec<u8>),是一个有效的 UTF-8 序列。String 是堆分配的,可增长的,且不是零结尾的。&str 是一个总是指向有效 UTF-8 序列的切片(&[u8]),并可用来查看 String 的内容,就如同 &[T]Vec<T> 的全部或部分引用。

自定义的错误特征,错误之间很可能会存在上下级关系,例如标准库中的 std::io::Errorstd::error::Error,前者是 IO 相关的错误结构体,后者是一个最最通用的标准错误特征,同时前者实现了后者,因此 std::io::Error 可以转换为 std:error::Error

在存在多个引用时,编译器有时会无法自动推导生命周期,此时就需要我们手动去标注,通过为参数标注合适的生命周期来帮助编译器进行借用检查的分析。

生命周期标注并不会改变任何引用的实际作用域

标记的生命周期只是为了取悦编译器,让编译器不要难为我们

​ ——RUST语言圣经

生命周期注释有一个特别的:‘static 。所有用双引号包括的字符串常量所代表的精确数据类型都是 &’static str ,’static 所表示的生命周期从程序运行开始到程序运行结束。

map 方法是一个迭代者适配器,它最大的好处不仅在于可以就地实现迭代器中元素的处理,还在于可以捕获环境值。它是惰性的,不产生任何行为,因此我们还需要一个消费者适配器进行收尾:

消费者适配器是消费掉迭代器,然后返回一个值。那么迭代器适配器,顾名思义,会返回一个新的迭代器,这是实现链式方法调用的关键:v.iter().map().filter()...

filter() 的闭包需要用一个引用,并且许多迭代器迭代引用,所以这可能导致混乱的情况,其中闭包的类型是双引用:通常在参数上使用解构来去掉一个

1
2
let mut iter = a.iter().filter(|x| **x > 1);
let mut iter = a.iter().filter(|&x| *x > 1);

flat_map()

map 适配器非常有用,但仅当闭包参数产生值时才使用。 如果它产生一个迭代器,则存在一个额外的间接层。 flat_map() 将自行删除这个额外的层。

特性(trait)概念接近于 Java 中的接口(Interface),但两者不完全相同。特性与接口相同的地方在于它们都是一种行为规范,可以用于标识哪些类有哪些方法。

特性在 Rust 中用 trait 表示:

格式是:

1
impl <特性名> for <所实现的类型名>

Rust 同一个类可以实现多个特性,每个 impl 块只能实现一个。

  • Box<T>,可以将值分配到堆上

  • Rc<T>,引用计数类型,允许多所有权存在

  • Ref<T>RefMut<T>,允许将借用规则检查从编译期移动到运行期进行.写链表的时候再回忆一下……

  • AsRef 是一个 trait(特质),用于将一个类型转换为另一种类型的引用。

  • AsRef 的作用是允许我们以统一的方式处理不同类型之间的转换。通过实现 AsRef trait,我们可以定义一个类型转换函数,该函数将一个类型转换为另一个类型的引用。

  • 如果我们有一个类型 T,并且希望将其转换为类型 U 的引用,我们可以实现 AsRef <U> trait 来完成这个转换。在实现中,我们需要提供一个名为 as_ref 的方法,该方法返回类型 &U。这样,我们就可以使用 as_ref 方法来将 T 转换为 U 的引用。

fn num_sq<T: AsMut>(arg: &mut T)

AsMut< >可变引用。其他同上

Rust 宏(Macros)是一种在编译时生成代码的强大工具,它允许你在编写代码时创建自定义语法扩展。

1
2
3
4
5
6
7
macro_rules! my_macro {
// 模式匹配和展开
($arg:expr) => {
// 生成的代码
// 使用 $arg 来代替匹配到的表达式
};
}

还有很多没写,笔记记在其他地方了,不过太零散了,有空整理一下。

一、引言

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

二、Rust语言深度探索

Rust以其内存安全性和高性能特性在操作系统开发领域受到广泛关注。在本阶段,我深入学习了Rust的核心概念,如所有权、借用检查器和生命周期管理等。这些特性确保了代码的安全性和可靠性,尤其在并发和内存管理方面表现优异。

通过编写简单的Rust程序,我逐渐掌握了语言的特性和风格。同时,我也浏览了Rust的标准库和生态系统,了解了其在并发编程、网络编程和系统级编程等方面的优势。

三、习题实践

为了巩固所学知识,我积极完成了训练营提供的Rust习题。这些习题涉及从基础语法到高级特性的各个方面,通过实践编程,我加深了对Rust语言的理解,并提高了编程技能。

四、算法

算法是操作系统设计中的关键部分,但是由于时间问题,我最后10个algorithms点到即止,后续在深入研究其思想。

五、Rust与操作系统的结合理解

通过本阶段的学习和实践,我深刻体会到了Rust在操作系统开发中的优势。Rust的内存安全性和并发性能使得它成为构建高效、稳定操作系统的理想选择。同时,Rust的丰富生态系统和活跃的社区也为开发者提供了强大的支持。

我也意识到,将Rust与操作系统知识相结合,不仅可以提升代码的质量和性能,还可以拓展操作系统的功能和特性。因此,在未来的学习和工作中,我将继续深化对Rust和操作系统的理解,探索更多结合两者的可能性。

六、总结与展望

本次训练营的第一阶段学习让我对Rust编程语言和有了更深入的理解。展望未来,我将继续深入学习Rust的高级特性和生态系统,探索更多与操作系统相关的应用场景。同时,我也将积极参与开源社区的建设,与同行交流学习,共同推动Rust在操作系统领域的发展。

最后,我要感谢训练营的组织者和导师们的辛勤付出和悉心指导。在未来的学习和实践中,我将继续努力,不断提升自己,为Rust和操作系统的结合做出更大的贡献。

总结

之前对rust有过了解和使用,所以做 rustlings 题目时主要以复习巩固为主,对之前没掌握好的细节再次通过文档等学了一遍,例如一些编译属性等等。最后10道算法题也比较考验对rust的理解,尽量控制unsafe的使用范围是其中挑战的地方。

同时翻看了一些risc-v的文档,单看文档理解不深,配合rCore-Tutorial-Book看效果更好一些

第一阶段的任务只是开胃小菜,希望后面第二阶段继续努力,全程follow完成所有的任务。