0%

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/

**

阶段一 Rust复习

因为本科期间用 Rust2021 比用c++20更多,所以对Rust的基本用法和tricks比较熟。所以最近时间更多用来做毕设。快到一阶段DDL时开始做 rustlings. 和 quiz.

  1. as_mut, as_ptr, as_ref, 以及rust2021引入的as_deref ,源码虽然都是一行,但是还是要注意很多细节的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    pub const unsafe fn as_mut<'a>(&mut self) -> &'a mut T {
unsafe { &mut *self.as_ptr() }

}
pub const unsafe fn as_ref<'a>(&self) -> &'a T {
unsafe { &*self.as_ptr().cast_const() }
// 实际上就是:
// unsafe {&*self.as_ptr() as *const T}
}

pub const fn as_ptr(self) -> *mut T {
self.pointer as *mut T
}

/// 该函数是Rust中是builtin的,命名为`cast_const`,它用于在不改变类型的情况下改变常量性(constness)。 该函数接受一个指向类型`T`的常量指针`self`作为输入,并返回一个指向类型`T`的常量指针。 它不会在代码重构时默默地改变类型。此外,虽然在大多数情况下,`*mut T`类型可以自动转换为`*const T`类型,但为了与`*const T`上的`cast_mut`函数保持对称性,所以该函数仍然需要(GPT)。 该函数是`const`函数,可以在编译时常量上下文中被评估,也是`inline`函数,总是会被内联到调用处。 该函数的返回类型是`*const T`,其中`T`是函数接受的指针类型`self`所指向的类型。
pub const fn cast_const(self) -> *const T {
self as _
}
  1. 重新复习了 Rust 的异步原语和基本的 tokio runtime.

  2. 对于 智能指针的 leak 方法,之前用的还挺少的。

  3. 参考 dbg! 写了一个 func_name, 使用它来做一些debug,在 no_std 下可能不能正常使用(还没试,有空到二阶段再

1
2
3
4
5
6
7
8
9
10
11
#[macro_export]
macro_rules! func_name {
() => {{
fn f() {}
fn type_name_of<T>(_: T) -> &'static str {
core::any::type_name::<T>()
}
let name = type_name_of(f);
name.strip_suffix("::f").unwrap()
}};
}
  1. 对lifetime的理解一直都不是那么到位。这次稍微注意了一下T: 'static, &'static T的差异

  2. Rust 的 FP 还是很舒服的。

  3. rustlings的 algo1.rs 那道题,没有想到用 safe 的方式怎么实现。那道题里面都是 unsafe, 还在卡顿中。而且我用了 NonNull::read_volatile, 很危险。

没有太多写的总结。一方面是不是很有空,另一方面是这算是一个复习。

二阶段会记录更多的东西。之前之做过 xv6 的labs,因为是时间问题,没有做 JYY OSLab 和 PA我一直觉得很遗憾。作为一个物理学学生,肯定是希望能在二阶段学到更多有趣的东西的。

第二次刷rustlings了,由于这次不用一章一章读《rust程序设计语言》,前面的题刷的比较快。但在后面一部分题慢了下来,主要原因是一些概念,要么现在记不清了,要么本来就没理解透,需要重新看资料。例如:迭代器好像就用了较长时间;第100题虽然参考微信群的提示和题目说明答了上来,但对外部块的引用机制还不是太明白。后面10道算法题主要参考了网上一些算法描述以及rust或其它语言的算法实现,再自己进行修改。从中了解了这些算法的原理,也可以看到别人实现时巧妙的地方。我觉得本次训练营这10道题添加的特别好。
我通过这次刷题,对rust语言的认识进一步加深,尤其是所有权机制。