Rust基础
Cargo
定义
- Cargo提供了一系列的工具,从项目的建立、构建到测试、运行直至部署,为Rust项目的管理提供尽可能完整的手段
命令
- 创建一个项目命令:cargo new 项目名称
- 手动编译:1、cargo build 这种代码的编译速度会非常快但是运行速度慢;原因是,在debug模式下,Rust编译器不会做任何的优化,只为了尽快的编译完成,让开发流程更加顺畅。2、cargo build --release:运行我们的高性能relese程序
- 运行项目:在运行项目时,现编译项目然后运行项目:cargo run
- cargo check:代码开发过程中最常用的命令;快速的检查一下代码能否编译通过. 该命令速度会非常快,能节省大量的编译时间.
文件
- cargo.toml:是cargo项目数据描述文件,存储了项目的所有元配置信息;构建cargo.toml能够让项目按照开发者期望的方式进行构建、测试和运行
- cargo.lock:是cargo工具根据同一项目的toml文件生成的项目依赖详细清单,一般不用修改它
基础入门
变量
- 变量不可变: let x=5,类型自行推导
- 变量可变性: let mut x=5 mut关键申请变量为可变
- 变量隐藏:前面申请的变量,程序后面可以在申请进行前段隐藏。如let x=" ";println!(x); let x=x.len();println!(x);
常量
- 使用const声明,Rust 常量的命名约定是全部字母都使用大写,并使用下划线分隔单词。如:const MAX_POINTS: u32 = 100_000;
数据类型
- 基本类型
- 数值类型
- 有符号整数:即可以取正数又可以取负数 i8, i16, i32, i64, isize
- 无符号整数:只能取正数 u8, u16, u32, u64, usize
- 浮点数 f32, f64
- 有理数
- 复数
- 序列(Range) 只能为数字和字符,常用于循环;1…5表示1到4;1…=5表示1到5
- 布尔类型 true和false
- 字符类型 let c = ‘z’;用单引号
- 元类型 元类型就是();main函数就返回这个元类型()
- 函数
- 函数定义:fn another_function(x: i32, y: f32) -> i32
- 函数定义参数时必须要定于数据类型,否则会报错
- 返回值有两种形式:1、return 返回值; 2、返回值— 注意没有;
- 数值类型
- 复杂类型
- 数组
- 数组声明
- let a = [1, 2, 3, 4, 5];
- let a: [i32; 5] = [1, 2, 3, 4, 5];声明类型和长度时中间用分号隔开
- 数组声明
- 字符串
- 字符串创建 String::from(“hello world”);
“hello world”.toString(); - 更新
- push_str 将&str类型的"hello,world"添加到中,s.push_str(“hello,world”);
- push 将字符’!‘推入s中,s.push(’!’);
let s1 = String::from(“tic”);
let s2 = String::from(“tac”);
let s3 = String::from(“toe”);
let s4 = s4.format("{}-{}-{}",s1,s2,s3);
使用format后以上3个变量可以正常再所有权中使用
+,let s = s1 + “-” + &s2 + “-” + &s3;
- 遍历
- chars()
- for c in “中国人”.chars() {println!("{}", c);}
- bytes()
- for b in “中国人”.bytes() {println!("{}", b);}
- chars()
- 切片(slice)
- 创建切片的语法,使用方括号包括的一个序列: [开始索引…终止索引]
- 字符串创建 String::from(“hello world”);
- 数组
所有权
- 内存
- 栈 1、申请空间大小固定,如:浮点数 2、变量赋值自动完成拷贝 如:let x=5;let y=x;此时x、y的值都为5;
- 堆 申请空间大小不固定,如:字符串;堆上分为浅拷贝和深拷贝,浅拷贝当变量值被赋予其它变量后,前面值将不再有效;深拷贝,通过clone完成变量的拷贝,前后两个值都有效,但是效率存在问题。
- 访问堆上的数据比访问栈上的数据慢,因为必须通过指针来访问。现代处理器在内存中跳转越少就越快(缓存)
- 例子
- 所有权规则
- 每一个值都有一个被称为其 所有者(owner)的变量。
- 值有且只有一个所有者
- 当所有者(变量)离开作用域,这个值将被丢弃
引用与借用
- 引用
- 引用为一个不可变的变量,如:let s = = String::from(“hello,world!”); let s1 = &s;
- 借用
- 获取可变引用为借用。如:let mut s = = String::from(“hello,world!”); let s1 = &mut s;
- 同一作用域,特定数据只能有一个可变引用:
- 可变引用与不可变引用不能同时存在,原因:可变引用可能改变前面得值,是前后数据不一致
- Non-Lexical Lifetimes(NLL)
- 新编译器可以通过编译, 引用作用域的结束位置从花括号变成最后一次使用的位置,因此 r1 借用和 r2 借用在 println! 后,就结束了,此时 r3 可以顺利借用到可变引用。
- 悬垂引用
- 指针指向某个值后,这个值被释放掉了,而指针仍然存在,其指向的内存可能不存在任何值或已被其它变量重新使用
结构体
- 结构体定义:使用关键字struct并为结构体提供一个名字;定义每个字段得名字和类型
- 创建结构体:实例需要以结构体的名字开头,接着在大括号中使用 key: value 键-值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。
- 更新字段值:通过user1.email = String::from(“anotheremail@example.com”);注:整个结构体必须事可变的,结构体不支持单个字段标记为可变。
- 结构体更新语法:
- 更新部分值
- 简写方法,使用… 语法指定了剩余未显式设置值的字段
- 类单元结构体:(unit-like structs)没有任何字段的类单元结构体,因为它们类似于 (),即 unit 类型。类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。
- 方法
- 定义:使用fn关键字和名称声明,可以拥有返回值和参数
- impl块:函数放入impl 大括号中,并将签名中的第一个参数和为self。
- 关联函数:在 impl 块中定义不以 self 作为参数的函数;使用结构体名和 :: 语法来调用这个关联函数:如 let sq = Rectangle::square(3);
- 多参数的方法:
- 符号说明
- {:?}
- {:#?}
枚举
- 枚举定义格式
- enum IpAddrKind {V4,V6,}
- enum IpAddr {V4(String),V6(String),} let home = IpAddr::V4(String::from(“127.0.0.1”));
- enum IpAddr {V4(u8, u8, u8, u8),V6(String),} let home = IpAddr::V4(127, 0, 0, 1);
- enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(i32, i32, i32),}
包和crate
- 定义
- crate 是一个二进制项或者库
- 包(package) 是提供一系列功能的一个或者多个 crate。一个包会包含有一个 Cargo.toml 文件
- 一个包中至多 只能 包含一个库 crate(library crate);包中可以包含任意多个二进制 crate(binary crate)
- 模块定义
- 定义
- 模块可以将 crate 中的代码进行分组,以提高可读性与重用性
- 私有性
- 被外部代码使用的(public)
- 不能被外部代码使用(private)
- 作用域
- 路径引用
- 绝对路径
- 绝对路径,从 crate 根开始;如:crate::front_of_house::hosting::add_to_waitlist();
- 相对路径
- 从当前模块开始,以 self、super 或当前模块的标识符开头。
- 绝对路径
集合
- vector
- 新建vector
- 创建一个新的空 vector:let v: Vec = Vec::new();
- 新建一个包含初值的 vector:let v = vec![1, 2, 3];
- 更新 vector
- 对于新建 vector 并向其增加元素,可以使用 push 方法
- 丢弃 vector 所有元素
- vector 在其离开作用域时会被释放
- 读取 vector 的元素
- 使用索引语法:let third: &i32 = &v[2];
- get 方法来访问 vector 中的项
- 遍历 vector 中的元素
- 依次访问 vector 中的每一个元素,我们可以遍历其所有的元素
- 使用枚举来储存多种类型
- Rust 在编译时就必须准确的知道 vector 中类型的原因在于第一需要知道储存每个元素到底需要多少内存。第二个好处是可以准确的知道这个 vector 中允许什么类型
- 新建vector
- HashMap
- 说明:HashMap是最不常用的,标准库中对HashMap的支持也相对较少,所以使用时需要引入use std::collections::HashMap;
- 新建一个哈希 map
- let mut scores = HashMap::new();
- 使用vec拉链形式:
- 访问哈希 map 中的值
- 更新HashMap
- 覆盖更新:
- 只在键没有对应值时插入:使用 entry 方法只在键没有对应一个值时插入
- 根据旧值更新一个值