崮生的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 打印 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 函数
fn main() {
fn add1(x: i32) -> i32 {
return x + 1;
}
}
闭包/lambda
为什么是竖线 : 与 Smalltalk 和 Ruby 的闭包定义类似
// rust 的 lambda,两个竖线所包裹的就是参数,后面是函数体,可以用花括号(代码块)来添加多条语句
let add3 = |w: i32| w + 3;
println!("{:?} {:?}", add1(6), add3(6))
move 强制闭包获取其使用的环境值的所有权
let equal_to_x = move |z| z == x; // 这里不使用 move 的话,下面还可以继续访问 x 的
Rust 结构体、元组、数组、vector、...
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);
}
println!("rust 元组 {:?} / {:?}", (1, 1_i8), (0, false, 1, true, (0, 1)));
// > rust 元组 (1, 1) / (0, false, 1, true, (0, 1))
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 类型是标准库提供的一个 允许 增长和缩小长度的类似数组的集合类型
let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3];
let v100 = &v[100]; // 这里当索引处没有对应值的时候会 panic
let v100 = v.get(100); // 这里返回的是 Option 💚
枚举
#[derive(Debug)] // 不需要 println 就不需要加这个
enum IpAddrKind {
V4,
V6,
}
fn main() {
println!(
"{:?} {:?}",
(|ip: IpAddrKind| ip)(IpAddrKind::V4),
IpAddrKind::V6
);
}
enum IpAddr {
V4(String),
V6(String),
}
对于
enum Option<T> { // 比 null 更好的选择
Some(T),
None,
}
迭代器
迭代器都实现了一个叫做
Iterator
的定义于标准库的 trait。
一些内置的工具类型
这些都在 prelude 中,不需要额外的命名空间指定
enum Result<T, E> { // 用来抛出可恢复错误
Ok(T),
Err(E),
}
let r: Result<i32, i32> = Result::Err(1);
r.unwrap(); // 在 r 匹配 Result::Err() 的时候 panic!
enum Option<T> { // 比 null 更好的选择
Some(T),
None,
}
Rust 控制流
fn main() {
let number = 3;
let number = if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
fn main() {
let number = 3;
// 注意! 这里的语法似乎不支持 return
let number = if number < 5 { "4" } else { "7" };
println!("{:?}", number);
}
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 控制流运算符
#[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 简单控制流
fn main() {
let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
println!("three");
}
}
错误 panic!
panic!("") // 抛出一个不可恢复的错误
-
-
传播错误的简写:? 运算符 放在函数调用括号的后面 , 当函数调用的返回值是
Result::Err
的时候直接 return 这个 err
-
泛型
struct Point<T> {
x: T,
y: T,
}
trait / 泛型约束 
rust 中通过 trait 来定义共享的行为 (我理解成约束)
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 语法
pub fn notify(item: impl Summary) -> impl Summary { // 函数参数以及返回值 约束!
println!("Breaking news! {}", item.summarize());
}
pub fn notify(item: impl Summary + Display) {} // 指定多个约束
pub fn notify<T: Summary>(item: T) { // 泛型约束
println!("Breaking news! {}", item.summarize());
}
fn some_function<T, U>(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 ),也就是引用保持有效的作用域。
&'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 程序设计语言 (rust-lang.org)
-
-
Debugging Rust ARM CortexM Programs with Visual Studio Code - DEV Community 🎉
-
这篇文章中有讲怎么在 vscode 中直接 debug 的,成功了❤
-
在
Rust 嵌入式开发环境搭建指南 (二):日常除虫 一文中也有讲怎么在 vscode 中 debug,但该文所用微处理器不同,我按照他的配置稍加改动也没有成功(应该是我太菜了)。
-
最佳实践
-
字符串
-
拼接
format!("{}-{}-{}", "a", "b", "c")
-
分割、获取标量list
"नमस्ते".chars()
-
闲评
-
Rust 的 Shadowing 特性 可能是为了弥补一个函数调用就将堆上的数据释放了,而如果通过 return 将所有权转移出来,这个时候如果没有 shadowing 特性命名会让人非常头疼
-
这里讲的真好, string 确实是个很复杂的东西 字节、标量值和字形簇!天呐!
by 崮生 from 崮生 • 一些随笔 🎨,欢迎 赞助本文
本文欢迎分享与聚合,全文转载未经授权( 联系我)不许可。