崮生的rust速览

速览系列

Cargo:Rust 的构建工具和包管理器

cargo build 可以构建项目
cargo run 可以运行项目
cargo test 可以测试项目
cargo doc 可以为项目构建文档
cargo publish 可以将库发布到 crates.io
cargo --version 检查是否安装了 Rust 和 Cargo
cargo new hello-rust 创建新项目

Rust 项目结构

hello-rust |- Cargo.toml |- src |- main.rs
Cargo.toml 为 Rust 的清单文件。其中包含了项目的元数据和依赖库。
src/main.rs​ 为编写应用代码的地方。

Rust 语法

rust
// rust 打印 log 方案, println!("{:?}+{1:#?}, {} + {1} = {2:?}", 1, 2, 3); println!("rust 字面量 数值 {},{1},{2},{3}", 1, 1_i8, 1_i16, 1_u16); println!("rust 字面量 数值 {},{1},{2},{3}", 1, 0x1, 0o1, 0b1);

Rust 函数

rust
fn main() { fn add1(x: i32) -> i32 { return x + 1; } }

闭包/lambda

为什么是竖线 : 与 Smalltalk 和 Ruby 的闭包定义类似
rust
// rust 的 lambda,两个竖线所包裹的就是参数,后面是函数体,可以用花括号(代码块)来添加多条语句 let add3 = |w: i32| w + 3; println!("{:?} {:?}", add1(6), add3(6))
move 强制闭包获取其使用的环境值的所有权
rust
let equal_to_x = move |z| z == x; // 这里不使用 move 的话,下面还可以继续访问 x 的

Rust 结构体、元组、数组、vector、...

rust
fn main() { #[derive(Debug)] // 不需要 println 就不需要加这个 struct User { username: String, email: String, } impl User { // 给结构体添加方法的语法 fn name_email(&self) -> String { let mut str: String = self.username.to_owned(); str.push_str("__"); str.push_str(&self.email); return str; } // 关联函数 fn init() -> User { User { username: String::from("someone"), email: String::from("someone@example.com"), } } } // 创建User 结构的实例, 需要修改则必须要可变 let mut user1 = User::init(); user1.username = String::from("崮生"); println!("{:?} {:?}", user1.name_email(), user1); // 使用结构体更新语法从其他实例创建实例 struct update syntax) let user2 = User { username: String::from("崮生2"), ..user1 }; println!("{:?} {:?}", user2.name_email(), user2); }
rust
println!("rust 元组 {:?} / {:?}", (1, 1_i8), (0, false, 1, true, (0, 1))); // > rust 元组 (1, 1) / (0, false, 1, true, (0, 1))
rust
let xs = [1, 2, 3, 4, 5]; let ys: [i32; 30] = [3; 30]; //长度 30,全部初始化为3 println!("rust 数组 {:?} / {:?}", xs, ys);

一些内置的实用类型

Map : std::collections::HashMap ,

vector

vector 类型是标准库提供的一个 允许 增长和缩小长度的类似数组的集合类型
rust
let v: Vec = Vec::new(); let v = vec![1, 2, 3]; let v100 = &v[100]; // 这里当索引处没有对应值的时候会 panic let v100 = v.get(100); // 这里返回的是 Option 💚

枚举

rust
#[derive(Debug)] // 不需要 println 就不需要加这个 enum IpAddrKind { V4, V6, } fn main() { println!( "{:?} {:?}", (|ip: IpAddrKind| ip)(IpAddrKind::V4), IpAddrKind::V6 ); }
rust
enum IpAddr { V4(String), V6(String), }
对于 null 问题 rust 中有 Option 枚举以及泛型,
rust
enum Option { // 比 null 更好的选择 Some(T), None, }

迭代器

迭代器都实现了一个叫做 Iterator 的定义于标准库的 trait。

一些内置的工具类型

这些都在 prelude 中,不需要额外的命名空间指定
rust
enum Result { // 用来抛出可恢复错误 Ok(T), Err(E), } let r: Result = Result::Err(1); r.unwrap(); // 在 r 匹配 Result::Err() 的时候 panic!
rust
enum Option { // 比 null 更好的选择 Some(T), None, }

Rust 控制流

rust
fn main() { let number = 3; let number = if number < 5 { println!("condition was true"); } else { println!("condition was false"); } }
rust
fn main() { let number = 3; // 注意! 这里的语法似乎不支持 return let number = if number < 5 { "4" } else { "7" }; println!("{:?}", number); }
rust
fn main() { let r = loop { println!("loop 可以作为表达式,下面的while不行"); break 42; }; while r != 0 { break; } for element in (1..r).rev() { println!("从41->1: {}", element); } }

math 控制流运算符

rust
#[derive(Debug)] // 不需要 println 就不需要加这个 enum IpAddrKind { V4, V6(String), } fn main() { let ip = IpAddrKind::V6("v6 ip".to_owned()); let ip_tag = match ip { IpAddrKind::V4 => "v4".to_owned(), IpAddrKind::V6(addr) => addr, }; println!("{:?}", ip_tag); // "v6 ip" }

if let 简单控制流

rust
fn main() { let some_u8_value = Some(0u8); if let Some(3) = some_u8_value { println!("three"); } }

错误 panic!

rust
panic!("") // 抛出一个不可恢复的错误
传播错误的简写:? 运算符 放在函数调用括号的后面 , 当函数调用的返回值是 Result::Err 的时候直接 return 这个 err

泛型

泛型数据类型
rust
struct Point { x: T, y: T, }
生命周期 也是泛型

trait / 泛型约束

rust 中通过 trait 来定义共享的行为 (我理解成约束)
rust
pub trait Summary {// 声明一个 trait 「Summary」 fn summarize(&self) -> String; fn summarize1(&self) -> String { // 可以添加一个默认实现 String::from("(Read more...)") } } pub struct Tweet { pub username: String, pub content: String, pub reply: bool, pub retweet: bool, } impl Summary for Tweet { // 实现 Summary fn summarize(&self) -> String { format!("{}: {}", self.username, self.content) } }

Trait Bound 语法

rust
pub fn notify(item: impl Summary) -> impl Summary { // 函数参数以及返回值 约束! println!("Breaking news! {}", item.summarize()); } pub fn notify(item: impl Summary + Display) {} // 指定多个约束 pub fn notify(item: T) { // 泛型约束 println!("Breaking news! {}", item.summarize()); } fn some_function(t: T, u: U) -> i32 where T: Display + Clone, // 指定多个约束 的语法糖 U: Clone + Debug {}

Rust 所有权很重要

所有权(系统)是 Rust 最为与众不同的特性,它让 Rust 无需垃圾回收(garbage collector)即可保障内存安全。因此,理解 Rust 中所有权如何工作是十分重要的。

所有权规则

首先,让我们看一下所有权的规则。当我们通过举例说明时,请谨记这些规则:
1.
Rust 中的每一个值都有一个被称为其 所有者owner )的变量。
2.
值在任一时刻有且只有一个所有者。
3.
当所有者(变量)离开作用域,这个值将被丢弃。
fn main() { let s1 = String::from("hello"); let s2 = s1; // 这里将 s1 的值给了 s2, 然后 s1 就不可访问了。这种行为叫做 move let s1 = takes_ownership(s2); //s2 的所有权交给了 takes_ownership,所以下面就不能再使用 s2 了 let s1_len = calculate_length(&s1); // 这里通过引用的方式使用 s1 ,s1 的所有权还在 println!("{} {}", s1, s1_len); fn takes_ownership(some_string: String) -> String { println!("{}", some_string); return some_string; } fn calculate_length(s: &String) -> usize { return s.len(); } }
可变引用 ,使用 &s 获得的值是无法修改的,需要使用 &mut s
可变引用有一个很大的限制:
在特定作用域中的特定数据只能有一个可变引用。(不可变引用可以有多个)
可变引用与不可变引只能选一个
Slices - Rust 程序设计语言 简体中文版 (kaisery.github.io)

生命周期

Rust 中的每一个引用都有其 生命周期lifetime ),也就是引用保持有效的作用域。
rust
&'a i32 // 带有显式生命周期的引用 &'a mut i32 // 带有显式生命周期的可变引用
静态生命周期 'static 在整个程序运行期间都存活

项目管理

crate 、 super
pub
pub use / 重导出
use
as
嵌套路径从一个模块导入多个 use std::{self,cmp::Ordering, io}; , 这里的 self == std
使用外部包 [dependencies]
glob 运算符 use std::collections::*;use std::collections 下的公有项全部引入作用域,看上去就是不应该随便用的

学习资料

Rust 程序设计语言 简体中文版

Rust 嵌入式

这篇文章中有讲怎么在 vscode 中直接 debug 的,成功了❤
Rust 嵌入式开发环境搭建指南 (二):日常除虫 一文中也有讲怎么在 vscode 中 debug,但该文所用微处理器不同,我按照他的配置稍加改动也没有成功(应该是我太菜了)。

最佳实践

字符串
拼接 format!("{}-{}-{}", "a", "b", "c")
分割、获取标量list "नमस्ते".chars()

闲评

Rust 的 Shadowing 特性 可能是为了弥补一个函数调用就将堆上的数据释放了,而如果通过 return 将所有权转移出来,这个时候如果没有 shadowing 特性命名会让人非常头疼
这里讲的真好, string 确实是个很复杂的东西 字节、标量值和字形簇!天呐!