泛型泛型编程是现代编程语言中重要的机制
C++是通过模板来实现泛型的,而C语言中是没有泛型的
泛型是用来表达抽象类型的机制,用于功能确定,但是数据类型不确定的类型
函数中的泛型下面这个是没有泛型版本的取数组中最大值的函数
12345678910111213141516fn max(array: &[i32]) -> i32 { let mut max_index = 0; let mut i = 1; while i < array.len() { if array[i] > array[max_index] { max_index = i; } i += 1; } array[max_index]}fn main() { let a = [2, 4, 6, 3, 1]; println!("max = {}", max(&a));&...
包管理Rust的包管理有三个重要的概念,分别是箱、包、模块
箱(Crate)这个Crate是二进制程序文件或者是苦文件,存在于包中
是树状结构,树根是编译器开始运行时编译的源文件所编译的程序
二进制程序文件不一定是可执行文件,只能确定是包含沐白哦机器语言的文件,文件格式主要取决于编译环境
包(Package)我们使用cargo new一个Rust工程时,这个工程其实就是一个包,包必须由Cargo.toml文件来管理,主要是描述包的基本信息和依赖项
一个包最多包含一个库Crate,但是可以包含任意二进制Crate,但是至少包含一个Crate
当我们创建完项目之后,会有一个main.rs,这其实就意味着这是一个二进制项目
模块(Module)Rust中组织的单位是模块,模块有很多中声明方式
例如
1234567891011mod nation { mod government { fn govern() {} } mod congress { fn legislate() ...
切片类型切片(Slice)是对数据值的部分“引用”
我们可以从一个数据集合中取一部分来使用
字符串切片例如
12345678fn main() { let s = String::from("broadcast"); let part1 = &s[0..5]; let part2 = &s[5..9]; println!("{}={}+{}", s, part1, part2);}
这里的0..5是前闭后开区间实际上内存上是这样的
有一些简便的写法,可以这样写
123..y 等价于 0..yx.. 等价于位置 x 到数据结束.. 等价于位置 0 到结束
被切片引用的字符串是不允许被修改的,除此之外,我们需要区分str和String这两个字符串类型
前者指的是堆内存中的字符串,我们可以理解为常量字符串,用的时候是作为&str引用使用的
String实际上是一种数据类型,类似于C++中的string类,有追加,清...
基于文件锁的进程监控机制在分布式系统或者一些需要长期运行的程序中,我们经常需要确保某些关键进程(如日志收集程序、服务守护进程等)一直在运行。如果进程意外退出或者崩溃,我们需要能够检测到,并及时做出响应。
在这种情况下,”文件锁(File Lock)” 机制是一种简单但有效的方式。本文将介绍基于文件的进程监控方式,并通过一个例子来帮助理解。
进程监控的核心思路通常,我们希望有一个监控机制,它能够:
确保某个进程正在运行
如果进程异常退出,可以检测到并触发报警或重启
机制本身要足够简单和可靠
一种常见的做法是使用 “PID 文件” 进行监控。
什么是 PID 文件?PID(Process ID)是操作系统为每个正在运行的进程分配的唯一标识符。我们可以让一个程序在启动时,将自己的 PID 写入一个文件(通常存放在 /var/run/ 目录下),然后定期检查这个文件。
如何监控进程?
程序启动时,创建一个 PID 文件,并把自己的 PID 写进去。
监控程序定期检查这个 PID 文件,看看里面记录的进程是否还在运行。
如果 PID 文件不存在,或者进程已经不在运行,就可以触发报警或自...
Rust所有权C/C++中我们对于堆内存通常需要自己手动管理,手动申请和释放,即便有了智能指针,对于效率的影响和安全性问题也没有完全解决
Rust为了高效的使用和管理内存,以及对安全性的考量,提出了所有权的概念以及一系列规则
所有权规则所有权有三条核心规则
Rust中的每个值都有一个隐含的变量,称为所有者
一个值 同一时刻只能有一个所有者
当所有者离开作用域时,值会被丢弃(调用drop函数释放资源)
12345678fn main() { let s1 = String::from("Hello"); // s1 是 "Hello" 的所有者 let s2 = s1; // s1 的所有权被转移给 s2,s1 失效 // println!("{}", s1); // ❌ 编译错误:s1 已经失去所有权 println!("{}", s2); // ✅ s2 仍然是 "Hello" 的所有者...
Rust迭代器迭代器适用于对集合进行逐个遍历操作的对象
迭代器是通过iterator trait来定义的,需要我们实现next方法,用于返回迭代器的下一个元素,如果没有下一个元素应该返回None表示结束
其他默认实现的方法有map filter等
12345pub trait Iterator{ type Item; fn next(&mut self) -> Option<Self::Item>;}
迭代器有以下的一些特性
惰性求值:这个意思是迭代器本身不回立即进行任何计算或者操作,除非我们显示的要求获取数据,迭代器才会返回数据,这样就可以避免不必要的计算
所有权和借用检查:迭代器严格遵守所有权和借用的规则,具体是什么我们后面会讲到,这里我们只要知道,这是为了避免数据竞争和内存错误
链式调用:Rust迭代器支持链式调用
抽象和通用性:Rust迭代器通过 Iterator trail实现抽象和通用性
迭代器的使用创建迭代器可以通过.iter() .iter_mut .into_iter()来创建迭代器
第一个是不可变引用...
闭包Rust中的闭包是一种匿名函数,可以捕获并存储环境中的变量,有点类似于Lambda表达式
闭包允许在其定义的作用域之外访问变量,并且可以在需要时将其移动或者借用给闭包
闭包在Rust中被广泛应用于函数式编程、并发编程和事件驱动编程等领域
比较适合用于短小的自定义逻辑的场景
1234let name = |参数列表| 表达式或语句块;let add = |x: i32| x + 1;let cal = |x, y, z| x * y + z;let res = cal(1, 2, 3);
捕获外部变量闭包可以捕获环境中的变量
123let x = 5;let add = |num| num + x;println!("{}", add(1)); // 输出 6
捕获变量有三种方法
传引用捕获(默认的,类似于 &T)
传值捕获(类似 T)
借用捕获(类似 &mut T)
1234567891011121314fn main(){ let mut num = 114; let print_num = ...
函数Rust的函数基本形式是这样的
123fn a_func(a: i32) -> i32 { }
函数名是蛇形风格,rust不在意函数的声明顺序,只需要有声明即可
函数参数必须声明参数名称和类型
语句与表达式这是rust非常重要的基础概念,我们可以认为函数体是由语句和表达式组成的
语句指的是执行某些操作并且没有返回值的步骤
例如
12let a = 5; // 正确let b = (let c = 1); // 错误 因为 let c = 1 没有返回值
表达式有计算步骤且有返回值,例如
123a = 7b + 1c * (a + b)
rust认为{}内也是一个表达式
12345let a = 1;let c = { let b = 1; a + b};
需要注意的是,表达式的返回值是 a + b,代表整个表达式的返回值,加上;之后就成了语句,就没有返回值了
返回值需要通过->声明返回值类型,但是rust不支持自动返回值类型判断
函数体表达式不允许有返回值,不能使用return
...