崮生的rust速览 Cargo:Rust 的构建工具和包管理器
cargo --version 检查是否安装了 Rust 和 Cargo
cargo new hello-rust 创建新项目
Rust 项目结构
hello-rust
|- Cargo.toml
|- src
|- main.rs
Cargo.toml 为 Rust 的清单文件。其中包含了项目的元数据和依赖库。
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))
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),
}
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,
}
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)
}
}
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 无需垃圾回收(garbage collector)即可保障内存安全。因此,理解 Rust 中所有权如何工作是十分重要的。
首先,让我们看一下所有权的规则。当我们通过举例说明时,请谨记这些规则:
1.
Rust 中的每一个值都有一个被称为其 所有者 ( owner )的变量。
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 。
在特定作用域中的特定数据只能有一个可变引用。(不可变引用可以有多个)
Rust 中的每一个引用都有其 生命周期 ( lifetime ),也就是引用保持有效的作用域。
rust
&'a i32 // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用
嵌套路径从一个模块导入多个 use std::{self,cmp::Ordering, io}; , 这里的 self == std
glob 运算符 use std::collections::*; 将 use std::collections 下的公有项全部引入作用域,看上去就是不应该随便用的
学习资料 Rust 嵌入式
这篇文章中有讲怎么在 vscode 中直接 debug 的,成功了❤
最佳实践
拼接 format!("{}-{}-{}", "a", "b", "c")
分割、获取标量list "नमस्ते".chars()
闲评
Rust 的
Shadowing 特性 可能是为了弥补一个函数调用就将堆上的数据释放了,而如果通过 return 将所有权转移出来,这个时候如果没有 shadowing 特性命名会让人非常头疼