语法基础
什么是 crate?
相当于类库。
crates.io 上有很多 Rust 社区成员发布的库。
创建和使用模块
通过执行 cargo new --lib restaurant
,来创建一个新的名为 restaurant
的库。
创建项目
cargo new hello_cargo
构建项目
cargo build
构建并运行
cargo run
只检查不生成
cargo check
定义一个模块,使用 mod
关键字:
#![allow(unused)]
fn main() {
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn server_order() {}
fn take_payment() {}
}
}
}
名称的引用:
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
front_of_house::hosting::add_to_waitlist();
使用 pub
关键字公开名称。
super
关键字类似 CLI’s ..
fn fix_incorrect_order() {
cook_order();
super::serve_order();
}
结构体
pub struct Breakfast {
pub toast: String,
seasonal_fruit: String,
}
于其上的方法及结构体的实例化
impl Breakfast {
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
use
关键字
将名称引入作用域
use crate::front_of_house::hosting;
as
关键字
类似于 typedef,别名
use std::io::Result as IoResult;
pub use
:
- 将名称引入作用域
- 并同时使其可供其他代码引入自己的作用域
路径分配律
use std::{cmp::Ordering, io};
// 等价于
use std::cmp::Ordering;
use std::io;
枚举
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
API 基础
向量
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
let mut v = Vec::new();
v.push(5);
let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2]; // or v.get(2);
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
字符串
let mut s = String::new();
let data = "initial contents";
let s = data.to_string();
let hello = String::from("السلام عليكم");
let mut s = String::from("foo");
s.push_str("bar");
let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // 注意 s1 被移动了,不能继续使用
散列表
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
Box
Rust 的 Box 类似 C++ 的 unique_ptr。二者都是单所有权智能指针,并且将数据放在堆中。区别在于 Box 不能为 null. c++ unique pointer VS rust ownership : rust
有关操作
分配
Box::new(Point {x: 1, y: 2});
解引用
boxed_point.deref();
// 不是 *boxed_point;!!
区别:pointers - Why is the return type of Deref::deref itself a reference? - Stack Overflow
销毁
drop(boxed_point);
Option
Option 是一个枚举
// 简化版
pub enum Option<T> {
Some(T),
None,
}
如何返回一个 Option:
// 不会 `panic!` 的整数除法。
fn checked_division(dividend: i32, divisor: i32) -> Option<i32> {
if divisor == 0 {
// 失败表示成 `None` 取值
None
} else {
// 结果 Result 被包装到 `Some` 取值中
Some(dividend / divisor)
}
}
模式匹配
match checked_division(dividend, divisor) {
None => println!("{} / {} failed!", dividend, divisor),
Some(quotient) => {
println!("{} / {} = {}", dividend, divisor, quotient)
},
}
解包
optional_float.unwrap()
self、&self 和 &mut self
如果一个参数中有个 某 self
self
:表示所有权转移到该方法中&self
其实是self: &Self
的简写,表示该方法是对此对象的不可变借用。类比 C++ 的const &type name
mut &self
类比 C++ 的&type name
,解除了不可变的限制 Structs · A Guide to Porting C and C++ code to Rust
()
类型
相当于 C++ 的 void
std::mem::replace
作用如下:
访问命令行参数
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
println!("{:?}", args);
}
环境变量
- std::env::Vars Vars in std::env - Rust
使用迭代器
- 使用 in 迭代
fn main() {
let v1 = vec![1,2,3,4];
for val in v1.iter() {
print!("{},", val)
}
}
- 判断是否是 last
fn main() {
let v1 = vec![1, 2, 3, 4];
for (i, val) in v1.iter().enumerate() {
print!("{}", val);
if i == v1.len() - 1 {
print!("\n")
} else {
print!(",")
}
}
}
- 迭代前跳过 1 个
fn main() {
let v1 = vec![1, 2, 3, 4];
for val in v1.iter().skip(1) {
print!("{},", val)
}
}
- 迭代中跳过 1 个
fn main() {
let v1 = vec![1, 2, 3, 4];
for (i, val) in v1.iter().enumerate() {
if i == 1 {
continue;
}
print!("{},", val)
}
}
文件
打印到 stderr
eprintln!("{}", "Error, world!");
use std::io::{self, Write};
let mut s = String::new();
io::stdin().read_line(&mut s).unwrap();
io::stderr().write_all(s.as_bytes()).unwrap();
进程
休眠 1s
use std::thread;
use std::time::Duration;
fn main() {
println!("睡啦!");
thread::sleep(Duration::from_secs(1));
println!("醒啦!")
}
转换
String to int
let my_int = my_string.parse::<i32>().unwrap();
let my_int: i32 = my_string.parse().unwrap();
整数间转换
let time: u64 = t as u64;
闭包
闭包是可以捕获环境的匿名函数
疑问:
- 捕获的是原来的变量,还是暂存到新的变量?
- 能否以某种方式修改原来的变量?
闭包可以通过三种方式捕获其环境,他们直接对应函数的三种获取参数的方式:获取所有权,可变借用和不可变借用。这三种捕获值的方式被编码为如下三个 Fn trait:
- FnOnce 消费从周围作用域捕获的变量,闭包周围的作用域被称为其 环境,environment。为了消费捕获到的变量,闭包必须获取其所有权并在定义闭包时将其移动进闭包。其名称的 Once 部分代表了闭包不能多次获取相同变量的所有权的事实,所以它只能被调用一次。
- FnMut 获取可变的借用值所以可以改变其环境
- Fn 从其环境获取不可变的借用值
futures
前置知识:move