文章目录
第一章: 认识Rust
编程环境
官网有着详细的描述的命令执行步骤
windows 推荐使用 ubuntu 子 环境执行 rust 环境搭建,
idea 插件也支持 使用wsl 环境了,这个非常的方便
设置 path 环境变量
以下是linux 的配置过程
-
加入环境变量
export PATH=“ H O M E / . c a r g o / b i n : HOME/.cargo/bin: HOME/.cargo/bin:PATH”
-
配置生效
source .bash_profile
更新rust
rustup update
卸载 rust
rustup self uninstall
Hello Rust
fn main(){
println!("hello Rust!");
}
-
编译
rustc main.rs
-
运行
./main
Hello Cargo
Rust 提供的构建工具和包管理器Cargo,
cargo new # 新建项目
cargo build # 编译项目
cargo check # 检查报告项目中的错误,但不编译任何文件
cargo run # 编译运行项目
cargo test # 测试项目
cargo doc # 构建项目文档
cargo publish # 发布库到 crates.io
cargo clean # 移除项目的target文件夹递归
cargo update # 更新所有依赖库
cargo new project_name 创建可执行的二进制程序
cargo new project_name --lib 创建库
cargo build --release 在发布前,优化编译项目,
第二章: 变量与数据类型
- std::collections 提供了4中通用的容器类型,: 包含 8种 数据结构
- 动态数组 分为 : 普通动态数组Vec 和 双端队列VecDeque
- 映射 分为 HashMap
- 字符串 包括 String等类型
变量和可变性
本质上是一种绑定语义,即将一个变量名与一个值绑定在一起。
另一个不同点是 : 变量默认是不可改变的。
变量声明
变量遵循先声明后使用
变量名: 必须字母、数组、下划线组成,字母却分大小写,且不可以以数字开头,也不能只有下划线
fn main() {
let x: i8 = 1;
let x = 1; // 等价于 let x:i32 = 1;
}
变量的可变性
对不可变变量二次赋值
let 声明的变量默认是不可变的,第一次赋值后不能再通过再次赋值来改变值,
如果赋值,会报错!!!
对可变变量二次赋值
可以 对 变量进行 mut 修饰,可以进行复制
fn main() {
let mut c = 3;
c = 5;
println!("x : {}", c)
}
Rust 语言安全性的一大体现
变量遮蔽
Rust 容许在同一个代码块中声明一个与之前已声明变量同名的新变量,新变量会遮蔽之前的变量,这样无法再去访问前一个同名的变量。——————变量遮蔽
fn main() {
let x = 3;
let x = x + 2;
let x = x * 2;
println!("x : {}", x);
let x = "Hello Rust";
println!("x:{}", x)
}
//x : 10
//x:Hello Rust
虽然是同样的变量名,但是不具有覆盖的作用,还是本质上的两个变量,只是恰巧与前一个变量名相同而已
常量
常量是指 绑定到一个表示符且不容许改变的值,一旦定义后就没有任何方法能改变其值了。
fn main() {
const MAX_NUM: u32 = 1024;
}
常量与不可变量的区别的是
- 常量名通常是全局变量,大写字母,且必须指定常量的数据类型
- 常量声明使用const关键字,且必须注明值的类型
- 通过
变量遮蔽
的方式可以让不可变量改变,但是常量不可以遮蔽,不能重复定义。- 常量可以在任何作用域中声明,包括全局作用域。
- 常量只能被赋值为常量表达式或数学表达式,不能是函数返回值,或是其他在运行时才能确定的值。
基本数据类型
数据类型是作为静态编译语言的基础。
基本数据类型有: 整数类型、浮点数类型、布尔类型、字符类型、范围类型。
整数类型
整数是指没有小数点的数字。
根据有无符号,分为 有符号整数,无符号整数。
长度 | 有符号 | 无符号 |
---|---|---|
8位 | i8 | u8 |
16位 | i16 | u16 |
32位 | i32 | u32 |
64位 | i64 | u64 |
128位 | i128 | u128 |
arch | isize | usize |
fn main() {
let integer1: u32 = 17; // 类型声明
let integer2 = 17u32; //类型后缀声明
let integer3 = 17; // 默认i32 类型
let integer4: u32 = 0b10001; // 二进制
let integer5: u32 = 0o21; // 八进制
let integer6: u32 = 0x11; // 十六进制
let integer7 = 50_000; // 数字可读性分隔符_
}
浮点数类型
浮点数为带小数点数组,
默认类型为 f64
- f32: 单精度浮点数,小数点后面至少有6位有效数字
- f64: 双精度浮点数,小数点后面至少有15位有效数字
fn main() {
let float1: f32 = 1.1; // 类型声明
let float2 = 2.2f32; // 类型后缀声明
let float3 = 3.3; // 默认f64类型
let float4 = 11_000.555_001; // 数字可读性分隔符
}
布尔类型 及 字符类型
let t: bool = true; //显示声明
let t = false; // 隐式声明
// Rust 是UTF-8 作为底层的编码,每个字符占4个字节
let z = 'z';
let zz = ‘Z';
let heart_eyed_cat = '猫头头像'
范围类型
常用来生成从一个整数开始另一个整数结束的整数序列,有左闭右开和全闭两种形式
fn main() {
print!("(1..5):");
for i in 1..5 {
print!("{}", i)
}
println!();
// rev 顺序反转
print!("(1..=5).rev :");
for i in (1..=5).rev() {
print!("{}", i)
}
println!();
let sum: i32 = (1..=5).sum();
println!("sum :{}", sum)
}
//(1..5):1234
//(1..=5).rev :54321
//sum :15
复合数据类型
元组、数组、结构体和枚举等
元组类型
由一个或多个类型的元组组合成的复合类型,使用小括号()把所有元素放在一起。元素类型可以不一致。但是元组长度在初始化固定死,不能再改变
fn main() {
let tup1: (i8, f32, bool) = (-10, 7.7, false);
let tup2 = (7.7, (false, 10));
let tup3 = (100,);
println!("{}, {}", tup1.0, (tup2.1).1);
println!("{}", tup3.0);
let (x, y, z) = tup1;
println!("x : {}, y : {} , z: {} ", x, y, z)
}
//-10, 10
//100
//x : -10, y : 7.7 , z: false
数组类型
与元组的类型区别:
- 类型必须保持一致
一样的是,长度也不可以发生变化
fn main() {
let arr1: [i32; 5] = [1, 2, 3, 4, 5]; // 第一种声明方式,确定类型和长度和初始值
let arr2 = [1, 2, 3, 4, 5]; // 第二种声明方式,隐式判断数据类型和数组长度
let arr3: [i32; 5] = [1; 5]; // 等价于 [1,1,1,1,1] 使用默认值初始化
let arr4 = [1; 5]; // 与arr3 含义一样
println!("{:?}", arr1);
println!("{:?}", arr2);
println!("{:?}", arr3);
println!("{:?}", arr4);
}
//[1, 2, 3, 4, 5]
//[1, 2, 3, 4, 5]
//[1, 1, 1, 1, 1]
//[1, 1, 1, 1, 1]
结构体类型
是自定义数据类型,通过struct 关键字加自定义命名,
struct ListNode {
val: i32,
next: Option<Box<ListNode>>,
}
例子
struct Student {
name: &'static str, // 1. & 以后都是属于类型的定义
score: i32,
}
fn main() {
let score = 59;
let username = "zhangsan";
let mut student = Student {
score, // 2. 变量名与结构体里面的字段名一样,可以忽略对应
name: username,
};
student.score = 60; // 3. 结构体实例默认是不可变的,且不容许只江某个字段标记为可变,如果要修改结构体实例必须在创建实例前就声明为可变的
println!("name:{} , score : {} ", student.name, student.score);
let student2 = Student{
name:"lisi",
..student // 4. 自动通过名称对应未显示设置值的字段以传入实例进行更新
};
println!("name:{} , score : {} ", student.name, student.score);
}
//name:zhangsan , score : 60
//name:zhangsan , score : 60
元组结构体
字段只有类型,没有名称
fn main() {
struct Color(i32, i32, i32);
let black = Color(0, 0, 0);
}
单元结构体
单元结构体是指没有任何字段的结构体,一般只用于特定的场景
struct Solution;
枚举类型
是一个自定义数据类型,通过enum关键字加自定义命名来定义。
使用 枚举名::枚举值 访问值
fn main() {
let color_no_param = ColorNoParm::Red;
match color_no_param {
ColorNoParm::Red => println!("{:?}", ColorNoParm::Red),
ColorNoParm::Yellow => println!("{:?}", ColorNoParm::Yellow),
ColorNoParm::Blue => Blue!("{:?}", ColorNoParm::Blue),
}
}
// Red
枚举内容带有String类型参数,类似于函数调用
#[derive(Debug)]
enum ColorParm {
Red(String),
Yellow(String),
Blue(String),
}
fn main() {
println!("{:?}",ColorParm::Blue(String::from("blue")))
}
//Blue("blue")
容器类型
std::collections 提供了4 种通用的容器类型
类型 | 容器 | 描述 |
---|---|---|
线性序列 | Vec | 连续存储的可变长数组 |
VecDeque | 连续存储的可变长双端队列 | |
LinkedList | 非连续存储的双向链表 | |
键值对 | HashMap<K,V> | hashMap |
BTreeMap<K,V> | B树 的有序键值对 | |
结合 | HashSet | 无序集合 |
BTreeSet | 有序结合 | |
优先队列 | BinaryHeap | 二叉堆的优先队列 |
Vec
Vec 是一种动态可变长的数组,即在运行时可增长或者缩短数组的长度。,
内存为连续内存快用于存储,只能存储相同类型元素。
fn main() {
let mut v: Vec<i32> = Vec::new();// 创建空的动态数组
let mut v1: Vec<i32> = Vec::with_capacity(10); // 创建指定容量的动态数组
let mut v2 = Vec![1,2,3];// Vec! 创建动态数组并且进行初始化,,并且会根据初始值自动推断动态数组的元素类型
// 添加
let mut v3: Vec<i32> = Vec::new();
v3.push(1);
v3.push(2);
v3.push(3);
// 修改
v3[1] = 5;
// 删除
// 1.删除最后一个
v3.pop();
// 2. 删除并返回指定索引的元素
let temp = v3.remove(1);
// 访问
// 1. 索引方式直接访问
let tem = v3[1];
// 2. get 方法访问,可避免索引越界
let tm1 = v.get(1); // 如果该索引的值不存在,返回None
// 遍历所有元素
for i in v3 {
println!(i)
}
// 遍历获取每一个元素的可变引用
for i in &mut v3 {
*i += 50; // 使用* 来追踪和修改元素值
println!(i)
}
}
VecDeque
双端队列是一种具有栈和队列特征的数据结构,
适合于只能在队列两端进行添加或删除元素操作的应用场景。
fn main() {
// 1. 创建
let mut v1: VecDeque<u32> = VecDeque::new(); // 创建空的队列
let mut v2: VecDeque<u32> = VecDeque::with_capacity(10); // 创建同时指定长度
// 2 修改
v1.push_back(10); // 添加到末尾
v1.push_front(1);// 添加到开头
// 3. 修改
v1[1]= 4;// 指定索引修改
// 4. 删除元素两种方式 ,
// 两者都会返回Option类型的值Some(2)
v1.pop_back();
v1.pop_front();
// 使用remove方法删除,并返回指定索引的元素
v1.remove(1) ;// 如果索引为空,返回None
// 5 访问
// 直接指定索引访问元素
v1[0];
// get 方法返回元素
v1.get(1);
}
HashMap
hash 不容许有相同的key,
fn main() {
// 1. 创建
let mut map: HashMap<&str, i32> = HashMap::new();//
let mut map1: HashMap<&str, i32> = HashMap::with_capacity(10);
// 2. 修改
// insert 插入数据
let zhangsan1 = map.insert("zhagnsan",85); // 如果存在,则服务覆盖,不存在则是插入
// 检查键是否有对应值,只进行没有值的操作 entry,or_insert
// entry
map.entry("zhangsan" ).or_insert(97);
// 修改值
for (_,val ) in map.iter_mut(){
*val += 2; // 每一个value + 2
}
// 删除键值对,返回要删除的值,,没有返回None
map.remove("zhangsan");
// 直接key 获取 或者 get 方法获取
}
字符串
字符串本身也是一种特殊容器类型,是有零个或多个字符组成的有限序列。
字符串创建
- 固定长度的字符串字面量str
- 可变长度字符串对象String
fn main() {
// &str 的创建
let s1 = "Hello Rust";
let s12 = String::from("hello Rsut");
let s13 = s12.as_str();
// 对象String 的创建
let mut s = String::new();
let s = String::from("hello reust");
let str = "hello, Rust";
let s = str.to_string(); // 转换
}
字符串修改
fn main() {
let s1 = "Hello Rust";
let s12 = String::from("hello Rsut");
let s13 = s12.as_str();
// 对象String 的创建
let mut s = String::new();
let s = String::from("hello reust");
let str = "hello, Rust";
let mut s2 = str.to_string(); // 转换
// 修改
// 1. 尾部添加
s2.push('R');
s2.push_str("RR");
// 2. 插入
s2.insert(5, ',');
s2.insert_str(5, ",,");
// 3. 使用 + or += 拼接
s2 += s1;
// 4. 使用format! 连接字符串
let s = format!("{}-{}-{}", s1, s2, s13);
// 5. 使用replace 和 replacen 替换
s2.replace("aa", "33");
s2.replacen("aa", "55", 1); // 替换数量
// 6 使用pop,remove,truncate, clear 删除字符
s2.pop();// 删除最后一个字符 返回Option<Char>
s2.remove(1);//删除指定索引字符
s2.truncate(9); // 删除字符串中从指定位置开始到结尾的全部字符
s2.clear();//删除全部字符
// 访问
// 长度
s2.len();
// 迭代器访问字符串类型
let bytes = s2.bytes();
for b in bytes {
print!("{} |", b)
}
for c in s2.chars() {
println!(c)
}
}
字面量和运算符
字面量: 由文字、数字或符号构成的值,他只能作为等号右边的值出现
运算符与其他语言一样