Rust-进阶¶
1 泛型Generics¶
**rust泛型也就是C++中的模板**。rust盒C++中对泛型的要求有一些不同,如下:
1. rust种**方法、函数的泛型必须要有类型限制**,比如,方法种对泛型进行的加法运算,就要给泛型添加`std::ops::Add`的限制。C++种可以加这方面的限制,也可以不加。
2. rust中**结构、枚举泛型则不需要加限制**。
rust 中泛型参数可以用任意有效的符号代替,但通常使用 T
、U
等代替。
1.1 函数泛型¶
- 示例
#![allow(unused)]
fn main() {
fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {
a + b
}
println!("{}",add(2,3));
}
- 可能的输出
5
1.2 结构泛型¶
- 示例
struct Point<T> {
x: T,
y: T,
}
fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
}
1.3 枚举泛型¶
- 示例
enum Option<T> {
Some(T),
None,
}
1.4 方法泛型¶
方法泛型需要注意的是使用 impl<T>
。
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
fn main() {
let p = Point { x: 5, y: 10 };
println!("p.x = {}", p.x());
}
1.5 泛型的具体化¶
这和**C++中模板的显式具体化**相同,为特点的类型定义规则。泛型会**优先匹配具体化**的实现。
#![allow(unused)]
struct Point<T> {
x: T,
y: T,
}
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
fn main() {
let p1:Point<f32> = Point{x:2.0,y:3.0};
println!("{}",p1.distance_from_origin());
}
1.6 const 泛型¶
rust中const泛型盒C++中的基本类型模板形参相同。泛型形参可以指定整形类型。
fn display_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) {
println!("{:?}", arr);
}
fn main() {
let arr: [i32; 3] = [1, 2, 3];
display_array(arr);
let arr: [i32; 2] = [1, 2];
display_array(arr);
}
- 可能的输出
[1, 2, 3]
[1, 2]
1.7 const 泛型表达式¶
rust的泛型表达式和C++20中的`concepts` 和 `requires`很像,也是编译器检测泛型参数是否满足表达式。
2 集合¶
3 特征 Trait¶
4 包管理¶
- Package:可以用来构建、测试和分享包
- WorkSpace:对于大型项目,可以进一步将多个Crate联合在一起,组织成WorkSpace
- Crate:一个由多个Module组成的树形结构,可以作为三方库进行分发,也可以生成可执行文件进行运行
- Module:可以一个文件多个模块,也可以一个文件一个模块,模块可以被认为是真实项目中的代码组织单元
一个真实项目中典型的 Package
,会包含多个二进制包,这些包文件被放在 src/bin
目录下,每一个文件都是独立的二进制包,同时也会包含一个库包,该包只能存在一个 src/lib.rs
:
.
├── Cargo.toml
├── Cargo.lock
├── src
│ ├── main.rs
│ ├── lib.rs
│ └── bin
│ └── main1.rs
│ └── main2.rs
├── tests
│ └── some_integration_tests.rs
├── benches
│ └── simple_bench.rs
└── examples
└── simple_example.rs
- 唯一库包:
src/lib.rs
- 默认二进制包:
src/main.rs
,编译后生成的可执行文件与Package
同名 - 其余二进制包:
src/bin/main1.rs
和src/bin/main2.rs
,它们会分别生成一个文件同名的二进制可执行文件 - 集成测试文件:
tests
目录下 - 基准性能测试
benchmark
文件:benches
目录下 - 项目示例:
examples
目录下
4.1 mod¶
模块可以嵌套,也可以放在同一个文件,也可以分离到各个文件
4.1.1 Module 的声明¶
rust 中的Module通过关键字 mod 模组名{...}
来声明,这种声明方式和 C++中命名空间一样 namespace 命名空间名{...}
。
4.1.2 Module 的引入¶
mod 模组名
表示从和模组同名的文件加载该模块的内容, 这一点和 C++中 include 或者 C++20 中 Module一样。
4.2 pub¶
rust pub 相当于C++中的public。rust中默认是private。
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
4.3 use¶
rust 中 use 和 C++中 using namespace很像,简短了在使用外部模组下内容时长长的模组路径。
- 示例
#![allow(unused)]
fn main() {
mod front_of_house;
// 使用front_of_house:hosting的作用域引入到当前文件中,可以直接使用其下的内容
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
}
4.3.1 use .. as 别名¶
作用:将引入的内容重新命名,避免引入的内容同名污染问题。
4.3.2 pub use¶
作用:当外部的模块项 A
被引入到当前模块中时,它的可见性自动被设置为私有的,如果你希望允许其它外部代码引用我们的模块项 A
,那么可以对它进行再导出。
#![allow(unused)]
fn main() {
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub use crate::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
}
4.4 self、super、crate¶
self
其实就是引用自身模块中的项super
代表的是父模块为开始的引用方式,类似../
crate
相当于模组的根目录,用于绝对路径导入模组方式
#![allow(unused)]
fn main() {
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
// 绝对路径
crate::front_of_house::hosting::add_to_waitlist();
// 相对路径
front_of_house::hosting::add_to_waitlist();
}
}
4.5 第三方包的引入¶
引入下第三方包中的模块操作步骤如下:
1. 修改 Cargo.toml
文件,在 [dependencies]
区域添加一行:rand = "0.8.3"
2. 此时,如果你用的是 VSCode
和 rust-analyzer
插件,该插件会自动拉取该库,你可能需要等它完成后,再进行下一步(VSCode 左下角有提示)
好了,此时,rand
包已经被我们添加到依赖中,下一步就是在代码中使用:
use rand::Rng;
fn main() {
let secret_number = rand::thread_rng().gen_range(1..101);
}