0%

Rust学习经验

作为经验分享,我不会写太多,一小篇足以

前言

Rust作为新时代的语言,其语法特性相对于以前的语言有着较大的差别,而且目前的Rust教程都是非常繁琐且没有梳理出一条很好的路线的,具体表现为既不是阶梯式也不是直接深入讲一个点,前后内容穿插令人无法理解。当然这也与Rust本身语言的特性相关,而并非完全是教程编写者的原因。

学习任何语言的思想都应该是读大量的项目源码,Rust也是如此,不过更应该先掌握Rust语法基础。

以下为Rust学习的部分参考资料:

官方学习文档

Rust圣经(可以看作官方文档的中文替代版)

THU-Rust学习建议

Rustlings

我的建议

先通过学习文档练习语法,然后刷Rustlings,学习过程中参考教程代码or别人的代码,通过crate doc文档查询相关crate源码

Rust特色分享

所有权与生命周期

众所周知,Rust同C++一样是没有GC的,虽然C++在C++11有过GC提案,但是并未有编译器实现(可以当作没有),在C++23移除。C++可以通过RAII控制资源,那么Rust也有智能指针可以实现RAII,但是本文不讨论这个。本篇的主角是所有权

既然我要聊所有权,那么我为什么要标注生命周期这个东西呢,那当然是因为所有权和生命周期息息相关,C++的内存安全问题基本上都是对于所有权和生命周期的错误使用导致的。而由于Rust中的所有权是在编译期进行的,对运行期的性能没有任何影响。

Rust的所有权有三个原则

  1. Rust 中每一个值都被一个变量所拥有,该变量被称为值的所有者
  2. 一个值同时只能被一个变量所拥有,或者说一个值只能拥有一个所有者
  3. 当所有者(变量)离开作用域范围时,这个值将被丢弃(drop)

下面将通过一段代码说明以上意思

1
2
3
4
5
6
7
8
9
10
fn main(){
let a = String::from("Hello Rust");
let b = a;//此时所有权转移到b
println!("{:?}", a); //Wrong !!!
let c = b.clone();//c通过克隆产生,不会拿走b所有权
{
let d = b;//d获得b的所有权,并在该代码段结束后drop
}
println!("{:?}", b); //Wrong !!!
}

当然这只是浅浅的一点例子,我无法在这说完,可以查看前言中的资料进行深入学习

生命周期

有一个关于很有意思的概念可以被应用于生命周期,我只会在此介绍这个概念。

三种映射

  1. 协变(covariant) T: R(T<’a>, T<’b>) = R(‘a, ‘b)。
  2. 逆变(contravariant) T: R(T<’a>, T<’b>) = ~R(‘a, ‘b),也就是若 ‘a<’b,则 T<’a> > T<’b>。
  3. 不变(invariant) T: R(T<’a>, T<’b>) = “<> 或 =”,也就是无法推导子类型关系

你会发现,看上面的概念是不是看不懂?

看不懂就对了,其实这个对于编程来说并没有什么卵用,只是一个很有意思的东西。

那么我们不从Rust的角度来看协变和逆变的概念。

A <: B 代表A是B的子类型
A -> B 以 A 为参数类型, 以 B 为返回值类型的函数类型
x : A 这里x是一个变量, 其类型为A

其实这里从继承关系来看就很好接受了,我们有三个类型如下:
A <: B <: C

这里A变成B、C是协变,B变成C是协变,C变成A、B是逆变,B变成A是逆变。

为什么呢?
定义如下:

协变(Covariance)是指子类向基类的转换.
逆变(Contravariance)是指基类向子类的转换.

是不是突然明白了

那这和生命周期有啥关系呢?

生命周期是有长短的,在哪开始在哪结束,那是不是就有变长变短,的概念了,协变和逆变的概念是不是就能套进去了?

1
2
3
4
5
6
7
8
9
10
fn main() {
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
} // ---------+

从上面可以看出显示看出r的生命周期和x的生命周期,那是不是生命周期变长的就是协变,生命周期变短的就是逆变了。

非常容易理解!

TODO!
PS:慢慢写

2024年春夏季开源操作系统训练营-基础阶段-rust编程

1. rust编程语言

在软件开发的广阔天地中,Rust以其独特的内存安全性和高性能特性,赢得了越来越多开发者的青睐。作为一位对Rust感兴趣的新手,我决定踏上这段基础学习的旅程,并在这里分享我的学习心得。

2. 学习之前对rust的了解

Rust是一种系统编程语言,它旨在提供内存安全性,而又不牺牲性能。它的主要特点包括所有权系统、生命周期和借用检查器,这些特性共同确保了程序在运行时不会出现内存泄漏或空指针引用等常见问题。在开始学习Rust之前,我先对其背景和发展历程进行了了解。Rust起源于Mozilla的研究项目,旨在为C++提供一种更安全、更高效的替代品。经过多年的发展,Rust已经成为了一个功能强大且稳定的编程语言,被广泛应用于各种领域,包括操作系统开发、网络编程、嵌入式系统等。

3. 基础语法与数据类型

Rust的语法简洁明了,与C++和Java等主流编程语言有许多相似之处。我开始从学习Rust的基本语法和数据类型入手,如变量声明、条件语句、循环结构等。Rust的数据类型包括整数、浮点数、布尔值、字符和字符串等,这些数据类型的使用与其他语言类似,但也有一些独特之处。例如,Rust中的变量默认是不可变的(immutable),如果需要修改变量的值,必须在声明时使用mut关键字将其标记为可变的(mutable)。这种设计有助于减少程序中的错误,提高代码的可读性和可维护性。

4. 所有权与借用

Rust的所有权系统和借用检查器是其内存安全性的核心所在。在学习过程中,我花了大量时间来理解这两个概念。所有权系统决定了谁负责一块内存区域的生命周期,而借用检查器则确保了在任何给定时间,一个值只能有一个可变引用或任意数量的不可变引用。通过编写一些简单的示例程序,我逐渐掌握了如何正确使用引用和所有权来避免常见的内存错误。这虽然是一个挑战,但当我看到程序能够安全地运行而不会出现内存问题时,我感到非常兴奋和满足。

5. 学习过程难点

rust-rustlings-2024-spring中前面题总体还比较容易进行,特别是后10道题,花费了不少时间,经过不断的分析解决,最终解决了这些试题。通过这些试题对链表等数据操作认识更加深刻。

6. 总结

通过这次Rust基础学习之旅,我对Rust有了更深入的了解和认识。虽然Rust的语法和概念相对复杂一些,但我认为这是值得的,因为它为我们提供了一种更加安全和高效的编程方式。

2024开源操作系统训练营第一阶段总结-黄文轩

本文是对OS训练营第一阶段的总结,重点谈谈在第一阶段学习Rust的过程中,印象比较深刻的一些知识点。

所有权

所有权是Rust中一个非常重要的特性,查看如下代码:

1
2
3
4
5
6
fn main() {
let s1 = String::from("Hello World");
let s2 = s1;

println!("{s2}");
}

执行let s2=s1语句后,s1就不能再使用了,也就是说s1将资源移动给了s2,原来的变量就不再用原先的值了。Rust明确了所有权的概念,如果一个变量拥有了一个资源的所有权,就要负责那个资源的回收和释放,主要目的是为了安全。

在使用函数时,也同样要注意:

1
2
3
4
5
6
7
8
9
fn foo(s: String) {
println!("{s}")
}

fn main() {
let s1 = String::from("Hello World");
foo(s1); // 所有权发生移动
foo(s1); // 出错
}

在第一次使用foo时,s1字符串的所有权就移动到了参数s上,在该函数回收栈空间时,这个字符串就被回收掉了,因此无法再打印这个字符串。

如下代码就不存在问题,因为foo将所有权转移出来:

1
2
3
4
5
6
7
8
9
10
fn foo(s: String) -> String {
println!("{s}");
s
}

fn main() {
let s1 = String::from("Hello World");
let s1= foo(s1);
foo(s1);
}

但是上述代码将所有权转移出来,有时还是麻烦了点,频繁转移所有权会显得很冗余,可以使用引用这个特性。

下述代码使用了引用:

1
2
3
4
5
6
7
8
9
fn foo(s: &String) {
println!("{s}");
}

fn main() {
let s1 = String::from("Hello World");
foo(&s1);
foo(&s1);
}

Box智能指针

如果一个变量,存的是另一个变量在内存的地址值,那么就被称为指针。普通指针是对值的借用,而智能指针通常拥有对数据的所有权,可以做一些额外操作,比如管理引用计数和资源自动回收。

标准库中常见的智能指针:

  • Box<T>:在堆内存上分配值
  • Rc<T>:启用多重所有权的引用计数类型
  • Ref<T>&RefMut<T>,通过RefCell<T>访问:在运行时而不是编译时强制借用规则的类型

本文着重介绍Box,即指向堆内存的智能指针,允许在堆上存储数据而非栈,没有其他性能开销。

常用场景:在编译时,某类型的大小无法确定。但使用该类型时,上下文却要知道它的确切大小。

1
2
3
4
fn main() {
let b = Box::new(5); // 存储在堆上
println!("b = {}",b);
}

在变量 b 在离开作用域时,同样会被释放。

同样可以作用于结构体:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct Point {
x: u32,
y: u32
}

fn foo() -> Box<Point> {
let p = Point {x:10, y:20};
Box::new(p)
}

fn main() {
// ....
}

在创建Point结构体时,其尺寸是固定的,所以它的实例会被创建在栈上。而在创建 Box<Point> 实例的时候会发生所有权转移:资源从栈上移动到了堆,原来栈的那片资源被置为无效。

可以对Box进行解引用,由于u8具有copy语义,所以解引用后,原来的boxed还能使用

1
2
3
4
5
6
7
fn main() {
let boxed: Box<u8> = Box::new(5);
let val: u8 = *boxed;

println!("{:?}",val);
println!("{:?}",boxed);
}

但是对于move语义的类型来说,就不适用了
Box同样可以作为函数参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#[derive(Debug)]
struct Point {
x: u32,
y: u32
}

fn foo(p: Box<Point>) {
println!("{:?}",p);
}

fn main() {
let b: Box<Point> = Box::new(Point{x:10, y:20});

foo(b)
}

前言

对于Rust和OS,其实之前也只了解过Rust但是并未深入学习和研究,恰好开源操作系统训练营的开班,然后就积极报名参加,进入了交流群。同时,rust语言博大精深且与之前学习的语言也存在差异,作为从业者而言,每天并没有太多的时间去专注于该训练营开展的活动,但是每天都会尽可能的抽出相应的时间进行学习Rust和OS,为了去挖掘更多其未知的知识,丰富自我,达到更高一个层次。

学习总结感悟

总体来说在第一阶段这个学习过程还是挺顺利的,因为在报名之后,我已经着手学习Rust的相关知识,且网络平台上存在许多大量的资源供学习参考。整个大约一个月学习过程中,曾经碰到过许多的问题,在网上阅读过很多的文章寻找相关答案,也和有在加入的微信群交流探讨,总体感觉Rust还是一个正在发展中的语言,从开始接触到深入探究,就能发现Rust是一门年轻的且充满潜力的编程语言并且Rust语言同时也兼顾了安全性和高性能,因而它是一门非常出色的系统编程语言,能够编写操作系统、数据库、区块链应用等对安全、性能都要求极为严苛的系统级软件。
Rust语言同时是一门优秀的生产力语言,出色的文档、完善且高效的工具链(cargo,rustup),能够快速进行各个层次(小的嵌入式、大到操作系统,从底层系统开发到网络应用开发,均能胜任)的应用的开发。而且Rust社区也在快速发展,不断地创新,不断地摸索,学习者可以在社区中交流探讨中摩擦出了灿烂的火花。

Rust学习

学习历程

学习最开始查找的资料就是Rust语言社区,一般来说一门语言、框架或者库出现后,人们应用它们,不只是因为自身的强大,更是因为其背后的生态圈。这里有相应的且完整的代码、丰富的配套资源以及官方的指导文档,大家互相促进,在一个良好的氛围中交流学习Rust是种非常nice的感觉。

  • 语法:相对而言,Rust的语法是挺特别的。因为有生存周期和借用检查这类独有的概念,所以语法上看上去是比较复杂。但是作为一种现代编程语言,大量使用了泛型,但是也带来代码可读性较差的问题。这个问题也很让人感到苦恼的,需要有耐心且保持积极心态去学习、去摸索。
  • 特性:内存安全性、并发性强、高性能、易用性、跨平台性和社区活跃
  • exercise:边学边练才能达到更好的效果,前大半的练习题都差不多是基础,很容易做,我大概花了一天的时间做完了前100道题,还剩下最后十道的算法题,这还是有点难度在的,其实最终还是得靠牢牢掌握Rust的语法、数据结构以及代码逻辑分析等,还是能很快的解决掉最后的十道题。在这个过程中,Rust难上手很关键的一点就是其严格的编译器,编译器会做尽可能多的检查,而且也十分详细地发现问题,这样可以提早消除安全隐患。所以编译器像一个好老师,及早扼杀你的bug,强制性要求你写出可以正常运行的正确代码
  • note:学习过程中没有笔记是不完美的,所以整理了学习笔记, 记录日常学习的过程以及学习的内容,对于理解不清晰的模块和问题会仔细梳理代码逻辑,这是锻炼思维能力的一种方法,同时这对我来说可以将几节甚至是几章的内容进行串联起来,可以建立起更牢固的知识框架。

    学习氛围

  • 微信群里积极交流,提出问题,解决问题
  • 老师督促,学生活跃
  • 技术性的学术氛围浓厚
  • 目标一致

    学习成果

    在第一阶段的学习中,掌握了rust基础,学习到操作系统相关的概念以及原理

    展望

    Rust 是一门全新的语言,它会带给我们前所未有的体验,同时也能提升通用编程水平,甚至于赋予我们全新的编程思想。希望能够在第二阶段上继续保持,再接再厉

    致谢

    在老师的悉心指导下和交流群互帮互助下,从最开始的 Hello World 起步,到深入系统地学习了操作系统的基本概念、原理。这使我对Rust和OS 有了更加全面和深入的理解。最后,衷心感谢清华大学的老师们为我们提供了这次难得的学习机会,还有两位教学的讲师,对我们授课讲学。
    这次学习经历对我们来说,无疑是非常宝贵的财富,在以后走的更长远。

    分享连接~

    《Rust语言圣经》:https://course.rs/about-book.html
    《Rust程序设计语言》:https://rustwiki.org/zh-CN/book/
    《Rust指南》:https://tourofrust.com/
    《深入浅出rust》:https://zhuanlan.zhihu.com/rust-lang
    https://link.zhihu.com/?target=https%3A//www.gitbook.com/book/rustcc/rustprimer/details
    Rust 语言中文社区:https://rustcc.cn/

训练营第一阶段总结

1. 参加训练背景

​ 其实去年秋就已经知道了这件事情,不过当时是大二,觉得太难了些,当时就是图一个乐子,报了一个名,甚至连 github的仓库都没有打开过,去年可以说是完全没有用心的。没有那个时间和心力去坚持下去。

​ 今年能够重新来过,要走出舒适区,我觉得对于我来说是一个挑战,我本身并没有学过 C++,对于C++的一些浅显的了解仅限于用它打过算法,看过一点点 C++ 的书,甚至 Python 都没有学过,基本上看 Rust 一开始是让我感觉不适应的,这100道题目前80道算是自己摸索模索,大家讨论勉强能够写出,后面的线程,不安全的块unsafe,智能指针,闭包等,其实都是云里雾里,只能说是似是而非,感觉十分不扎实。

​ 不过令人庆幸的是,能够找到志同道合的队友,虽然我在我们的小队中一般是进度最慢的,另外两个队员给了我很多帮助,我有很多的疑问不解他们都会与我讨论,每天都有讨论的乐趣与激情,每晚10点30分就是到了今日学习总结分享的小队时间,这个时候大家的思想融汇贯通,是最能让人收获乐趣的。

​ 进度还是慢了很多,差不多一周半慢慢悠悠的混过去了第一阶段,遗憾是思维导图没有时间去做了,预计要拿出时间进行复盘。

​ 特此鸣谢两位志同道合的队友(theOnlyUniqueccaikano),有人共行是一大乐事

2. 参考书籍

​ 在学习 Rust 语言基础中,Rust 程序设计语言 - Rust 程序设计语言 中文版 (rustwiki.org)对我影响巨大,这本书力图教会我们从程序设计的思想上进行思考,考虑这段代码可能会出现的问题,以及他人看这段代码可能会出现的情况,在认真阅读过这本书之后,实在是令人受益匪浅。

3. 编译器报错

​ 编译器报错是成功之母!! 我写 C++ 都没有这么多报错!! Rust 编译器的报错真是让人想要吐槽,动不动就报错,不过令人欣慰的是,编译器的错误提示很精准,这令人感官十分良好,唯一麻烦的就是要逼着我去阅读编译器报错信息,这是程序员的基本功,但是还是很讨厌!

​ 在面对Rust 中的频繁报错时,尽量学会和编译器做朋友,他能够帮助你很多很多。

4. 资源分享

Tips: 嘿嘿嘿,就厚颜无耻的 借用一下 我队员的资源分享吧,你们偷偷看,把这个当成我的资源分享也是可以的 !!

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

2std - Rust (rustwiki.org)

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

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

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

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

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

来源 : 2024春季开源操作系统训练营刘启东一阶段总结

CreatorHell LearningOS 第一阶段总结

智能指针

  • Box:这是一种在堆上分配内存并管理所有权的智能指针。它允许你在堆上创建数据,并且当你不再需要这些数据时,Box会自动释放它们所占用的内存。
  • Rc:这是一种用于引用计数类型的智能指针,它允许多个所有者同时拥有同一个数据。当最后一个所有者离开作用域时,Rc会自动减少引用计数,并在计数达到零时释放内存。
  • Arc:与Rc类似,Arc也是引用计数类型,但它是线程安全的,可以在多线程环境中使用。
  • Cow<’a, T>:这是一种写时克隆(Clone-on-Write)的智能指针,类似于虚拟内存管理的写时复制。它包含一个只读借用,如果调用方需要所有权做修改操作,它会克隆借用的数据。

    所有权

  • 所有权概念:在Rust中,每个值都有一个被称为其所有者(owner)的变量,且每个值有且只有一个所有者。这意味着当一个变量被创建时,它就被分配给了一个特定的所有者。
  • 作用域关联:值的生命周期与其所有者的作用域相关联。当所有者变量离开其作用域时,值将被清理,从而防止内存泄漏。
  • 移动语义:当值从一个作用域移动到另一个作用域时,原作用域将失去对该值的所有权。这个过程称为移动(move),它是Rust内存管理的关键部分,有助于减少不必要的数据复制。
  • 借用机制:虽然Rust的所有权原则保证了内存安全,但它也引入了借用机制来允许多个引用同时访问数据。借用分为可变借用和不可变借用,它们通过借用检查器来确保数据的并发安全。
  • 克隆与复制:对于实现了Clone trait的类型,可以通过调用clone方法来创建数据的副本。而对于实现了Copy trait的类型,数据会在赋值或作为参数传递时自动复制,这适用于那些可以安全地复制数据的情况。

    多线程

  • 线程创建:在 Rust 中,可以使用标准库中的 std::thread 模块来创建新的线程。通过 spawn 函数可以启动一个线程,该函数接受一个闭包(匿名函数),这个闭包将在新线程中运行。
  • 线程控制:创建的线程可以通过 join 方法等待其执行完毕。如果主线程结束而子线程还在运行,Rust 会触发 panic 以防止资源泄露。因此,通常需要调用 join 或 detach 来避免这种情况。
  • 线程安全:Rust 的所有权和借用机制有助于保证多线程环境下的内存安全。当需要在多个线程间共享数据时,可以使用 Arc, Mutex, RwLock 等智能指针来确保同一时间只有一个线程能够访问或修改数据。
  • 消息传递:对于需要线程间通信的场景,Rust 提供了消息传递机制,如 mpmc(Multiple Producer, Multiple Consumer)队列,允许多个生产者和消费者线程安全地交换信息。

前言

由于对操作系统的相当的感兴趣,很巧的是当时在网上不经意间看到了这个开源操作系统训练营的相关信息,就赶紧报名参加了,同时这也是我第一次参加这样的开源课程,也是我第一次很深入的来学习操作系统的相关知识 ,对Rust也不是很了解,在报名之后就开始查找相关的资料学习了点Rust,去学习一个不熟悉的语言和框架,其实对我而言是非常有挑战性的一次学习旅程。

第一阶段学习总结

总体来说在第一阶段这个学习过程还是有点痛苦的,因为学习Rust的过程中我需要查阅许多相关的资料去了解相关知识点,同时,在学习的过程也会出现许多前所未有的问题,这就需要找方法解决,开始了一种循环模式。不过慢慢的能掌握,同时做练习也更能帮助我理解,总体还是较为顺利的!

Rust的学习

学习历程

rust语言学习起来还是挺困难的,难度比较高,我是通过《Rust语言圣经》这本书边学边看,还同时参考了《Rust程序设计语言》、Rust 语言备忘单等,遇到不会的看书再者看网上的教学边看边学,Rust虽然难度高但是从性能上和从安全性上都是非常不错的,优势也很突出!就比如rust最具特色的就是他的内存所有权机制。一块内存只能有一个所有者。当遇到和函数的参数传递的时候,所有权便会转移。rust中没有Null这个关键字,有的只是Option枚举类型。这就是其他语言所不具备的特性。
其实这个阶段主要还是作业练习这一块占有很大的比重,刚开始都是较为简单的语法题目,很好上手,越到后面的难度就逐渐往上升,特别是test和algorithm这一块,需要好好掌握rust的基础语法和rust实现数据结构算法等相关知识,将其灵活巧妙的运用起来。
在学习过程中整理了学习笔记, 对于理解不清晰的模块和问题会仔细梳理代码逻辑直到过程清晰,这对我来说是个非常好的掌握方法,可以将一些几节甚至是几章的内容进行串联起来,对前面的内容进行快速的梳理。

学习氛围

交流群内大家互帮互助,起到了很好的交流作用
方向一致,共同进步
技术技巧性的学术氛围浓厚
师生交流,积极沟通

学习成果

在第一阶段的学习中,我掌握了rust基础,逐渐学习操作系统相关的知识。通过和群友的交流分析,我也展开了对更多其它知识点的思考,在进一步讲在学习更多Rust关于智能指针和并行方面内容后,关于Rust的安全性保障和性能保障这两方面的疑惑又加深了。Rust在尽可能为安全保驾护航,它也做得非常好,但确实有时为了保障安全需要牺牲性能,这也许是不可避免地,Rust在尽可能做到最好。

展望

Rust 是一门全新的语言,它会带给我们前所未有的体验,同时也能提升通用编程水平,甚至于赋予我们全新的编程思想。我希望能够坚持完成第二阶段的学习,完善Rust的知识体系,深入了解操作系统带来的魅力。

致谢

首先十分感谢陈渝,向勇老师提供的这次参与夏令营的机会,其次是非常感谢给我们第一阶段讲课的两位讲师,认真负责并且提供帮助,我也成功的完成了第一阶段的学习。

参考资料

《Rust语言圣经》:https://course.rs/about-book.html
《Rust程序设计语言》:https://rustwiki.org/zh-CN/book/
《Rust指南》:https://tourofrust.com/
Rust 语言备忘单:https://cheats.rs/
Rust教程:https://www.youtube.com/
Rust 语言中文社区:https://rustcc.cn/

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

写在前面

今年三月初的时候被推荐了这个训练营,当时只抱着功利的目的想着参加这个训练营提升一下自己的能力,也丰富一下自己的履历,但是在学习的过程中逐渐发现了rust语言和操作系统的魅力,不知不觉也坚持做完了第一阶段

对于刚参加训练营的我来说,无论是Rust,Risv-v,还是OS,彼时都是一个较为陌生的概念,虽然本科是计科但是自己掌握的知识其实很有限,而且OS是这学期才开的课所以也没什么基础,每天看着群里大佬们的聊天都感觉自己大学是不是白学了,也是在那个时候下定决心要认认真真的学习

emm…不管怎么样,在复习考研,准备公司面试,进实验室打工的种种压力之下,我还是糊里糊涂地开始了自己的学习历程,并且有幸能够坚持下来

学习内容

主要参考的学习资料:关于本书 - Rust语言圣经(Rust Course) 以及 网上各路大佬的博客

印象比较深刻的内容:

Rust的对象所有权机制,生命周期,Option和trait等概念的引入,宏编程,unsafe机制,智能指针,多线程

尤其是智能指针的概念,让我对对象内存分配机制,以及Rust的安全机制和Java中的GC机制有了更深的理解

Rustlings前面的100道题总体来说比较简单,根据参考资料和编译器的错误提示基本都能解决出来,有几个题目有点小疑问的通过大佬们写的博客也能够顺利解决

最后10道题目应该是难度比较大,在这个地方卡了一段时间,不过后面看了一些资料之后也尝试着自己做了出来,只不过用了不少unsafe😔,以后有时间的话希望能把rust的知识再深入巩固一下,看看这部分的题目有没有更好的做法

最后,在一阶段到二阶段这个期间,希望自己能够根据大佬们的提示赶快把指令集架构和rCore的基本知识先看一下吧

学习心得 后续

虽然做完了rustlings的110道题目,但是我深知我自己对rust的理解只能说是迈出了第一步,如果离开了chatGPT的帮助和网上大佬写的博客我可能rustlings还要做好久吧😔

以及后续趁着自己有时间赶快把OS和Risv-v的知识再巩固一下

希望自己能把第二阶段rCore的内容跟下来吧

2024-04-27

在RUST中文社区看到这个活动,从组队到因停电用手机参加开营仪式,到每周一三五参加线上课程学习。

因之前用写过rust程序,有一定基础,但写rustlings还是有一定难度,对泛型、生命周期以及智能指针
还有许多知识要加强

rust相关的问题

rust标准库中重名方法太多,要熟悉常用的数据类型的方法

实现堆栈

以前没实现过堆栈,对此没有概念,加上用rust写堆栈繁琐,这方面要多补充

完成第一阶段期间用到的一些链接

API文档


Table of Contents

  1. rustlings
    1. conversions
      1. as
      2. frominto
      3. fromstr
      4. tryfrominto
      5. asrefmut
    2. unsafe
      1. modify by address
      2. raw pointer to box
    3. build.rs
    4. extern
    5. 算法

rustlings

conversions

as

fn average(values: &[f64]) -> f64 {
    let total = values.iter().sum::<f64>();
    total / values.len() as f64
}

frominto

struct Person{}


impl From<&str> for Person {
    fn from(s: &str) -> Person {
    }
}
// then you can use

let p = Person::from("Mark,20");

fromstr

//可以自定义错误
impl FromStr for Person {
    type Err = ParsePersonError;
    fn from_str(s: &str) -> Result<Person, Self::Err> {
    }
}

tryfrominto

// 与from类似,但可以定义转换错误处理
// Tuple implementation
// https://doc.rust-lang.org/std/convert/trait.TryFrom.html


// Tuple implementation
impl TryFrom<(i16, i16, i16)> for Color {
    type Error = IntoColorError;
    fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
        let red = u8::try_from(tuple.0).map_err(|e| IntoColorError::IntConversion)?;
        let green = u8::try_from(tuple.1).map_err(|e| IntoColorError::IntConversion)?;
        let blue = u8::try_from(tuple.2).map_err(|e| IntoColorError::IntConversion)?;

        Ok(Color { red, green, blue })
    }
}

//可见,从i16->u8 可以使用 u8::try_from(i16)

asrefmut

https://doc.rust-lang.org/std/convert/trait.AsRef.html

unsafe

modify by address

  1. raw pointer to ref

    pub struct Adapter<T: Driver>(T);
    
    impl<T: Driver> driver::DriverOps for Adapter<T> {
    type RegType = bindings::pci_driver;
    
    unsafe fn register(
            reg: *mut bindings::pci_driver,
    ) -> Result {
            // SAFETY: By the safety requirements of this function (defined in the trait definition),
            // `reg` is non-null and valid.
            let pdrv: &mut bindings::pci_driver = unsafe { &mut *reg };
    
            pdrv.name = name.as_char_ptr();
    
            //...
    }
    }
//linux/rust/kernel/net.rs

unsafe extern "C" fn get_stats64_callback(
        netdev: *mut bindings::net_device,
        storage: *mut bindings::rtnl_link_stats64,
) {
        // SAFETY: The C API guarantees that `net_device` isn't released while this function is running.
        let dev = unsafe { Device::from_ptr(netdev) };
}


impl Device {
/// # Safety
///
/// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the
/// returned [`Device`] instance.
pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::net_device) -> &'a Device {
        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
        // `Device` type being transparent makes the cast ok.
        unsafe { &*ptr.cast() }
}
}
  1. ref to raw pointer

    //linux/rust/kernel/net.rs
    
    impl<T: NapiPoller> NapiAdapter<T> {
    /// Creates a new Napi object.
    pub fn add_weight(dev: &Device, weight: i32) -> Result<Pin<UniqueArc<Napi>>> {
            let mut napi = Pin::from(UniqueArc::try_new(Napi::new())?);
    
            unsafe {
            bindings::netif_napi_add_weight(
                    &*dev as *const Device as *mut bindings::net_device,
                    napi.as_mut().0.get(),
                    Some(Self::poll_callback),
                    weight,
            )
            }
            Ok(napi)
    }
    }
  2. &[u8] to core::ffi::cchar

#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
unsafe fn printk(&self, klevel: &[u8], msg: fmt::Arguments<'_>) {
        // SAFETY: `klevel` is null-terminated and one of the kernel constants. `self.raw_device`
        // is valid because `self` is valid. The "%pA" format string expects a pointer to
        // `fmt::Arguments`, which is what we're passing as the last argument.
        #[cfg(CONFIG_PRINTK)]
        unsafe {
        bindings::_dev_printk(
                klevel as *const _ as *const core::ffi::c_char,
                self.raw_device(),
                c_str!("%pA").as_char_ptr(),
                &msg as *const _ as *const core::ffi::c_void,
        )
        };
}

raw pointer to box

/// # Safety
///
/// The `ptr` must contain an owned box of `Foo`.
unsafe fn raw_pointer_to_box(ptr: *mut Foo) -> Box<Foo> {
    // SAFETY: The `ptr` contains an owned box of `Foo` by contract. We
    // simply reconstruct the box from that pointer.
    let mut ret: Box<Foo> = unsafe { Box::from_raw(ptr) };
    ret
}

build.rs

set env

let timestamp = std::time::SystemTime::now()
    .duration_since(std::time::UNIX_EPOCH)
    .unwrap()
    .as_secs(); // What's the use of this timestamp here?
let your_command = format!(
    "rustc-env=TEST_FOO={}",
    timestamp
);
println!("cargo:{}", your_command);

set feature

// In tests8, we should enable "pass" feature to make the
// testcase return early. Fill in the command to tell
// Cargo about that.
let your_command = "rustc-cfg=feature=\"pass\"";
println!("cargo:{}", your_command);

extern

//提供ABI接口

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

//使用ABI

extern "Rust" {
    fn my_demo_function(a: u32) -> u32;
    fn my_demo_function_alias(a: u32) -> u32;
}

算法

二叉搜索树

https://www.hello-algo.com/chapter_tree/binary_search_tree/

**