fn main() {
let mut v = vec![1,2,3];
v.push(1);
let t = v[2];
println!("数值是 {}", t);
match v.get(3) {
Some(i) => println!("第三个索引是 {}", i),
None => println!("There is not third element")
}
}
use std::collections::HashMap;
fn main() {
let teams = vec![String::from("blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
}
fn main() {
let items = vec![1,2,3,4];
println!("Result is: {}", sum(&items));
println!("Items is {:?}", items);
}
fn sum(item: &Vec<u32>) -> u32 {
let iter = item.iter();
let mut result = 0;
for current_item in iter {
result = result + current_item;
}
result
}
use std::rc::Rc;
enum List {
Cons(i32, Rc<List>),
Nil,
}
fn main() {
let a = Rc::new(List::Cons(5, Rc::new(List::Cons(10, Rc::new(List::Nil)))));
// 不会执行数据的深度拷贝,只会增加引用计数
let b = List::Cons(10, a.clone());
println!("count {}", Rc::strong_count(&a));
let c = List::Cons(20, a.clone());
println!("count {}", Rc::strong_count(&a));
}
use std::cell::RefCell;
pub trait Messenger {
fn send(&self, msg: &str);
}
pub struct LimitTracker<'a, T: Messenger> {
messenger: &'a T,
value: usize,
max: usize,
}
impl<'a, T> LimitTracker<'a, T>
where
T: Messenger,
{
pub fn new(messenger: &T, max: usize) -> LimitTracker<T> {
LimitTracker {
messenger,
value: 0,
max,
}
}
pub fn set_value(&mut self, value: usize) {
self.value = value;
let percentage_of_max = self.value as f64 / self.max as f64;
if percentage_of_max >= 1.0 {
self.messenger.send("Error: You are over your quota!");
} else if percentage_of_max >= 0.9 {
self.messenger
.send("Urgent warning: You've used up over 90% of your quota!");
} else if percentage_of_max >= 0.75 {
self.messenger
.send("Warning: You've used up over 75% of your quota!");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockMessenger {
sent_messages: RefCell<Vec<String>>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messages: RefCell::new(vec![]),
}
}
}
impl Messenger for MockMessenger {
fn send(&self, message: &str) {
// 如果按照实现的话,self是不需要进行mut
// 按照测试的方法,self是需要进行mut,将值变为mut
self.sent_messages.borrow_mut().push(String::from(message));
}
}
#[test]
fn it_sends_an_over_75_percent_warning_message() {
let mock_messenger = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
limit_tracker.set_value(80);
// 使用borrow获取不可变引用
assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
}
}
5. 联合使用Rc\ 和RefCell\结合使用
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
enum List {
Cons(Rc<RefCell<i32>>, Rc<List>),
Nill,
}
fn main() {
let value = Rc::new(RefCell::new(5));
let a = Rc::new(List::Cons(value.clone(), Rc::new(List::Nill)));
let b = List::Cons(Rc::new(RefCell::new(10)), a.clone());
let c = List::Cons(Rc::new(RefCell::new(2)), a.clone());
*value.borrow_mut() += 10;
println!("a after = {:?}", a);
println!("a after = {:?}", b);
println!("a after = {:?}", c);
}
use std::thread;
fn main() {
let v = vec!([1,2,3]);
// 强制闭包获得它所需要值的所有权
let handle = thread::spawn(move || {
println!("你好 {:?}", v);
});
handle.join();
}
2. 消息传递
通过使用mpsc::channel函数创建了一个新的通道。路径中的mpsc是英文“multiple producer, single consumer”(多个生产者,单个消费者)的缩写。简单来讲,Rust标准库中特定的实现方式使得通道可以拥有多个生产内容的发送端,但只能拥有一个消耗内容的接收端(和rust的所有权保持一致)
use std::thread::spawn;
use std::sync::mpsc;
use std::thread::sleep;
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone();
let handle = spawn(move || {
let val = vec![
String::from("hello"),
String::from(" "),
String::from("world"),
];
for v in val {
tx.send(v).unwrap();
sleep(Duration::from_secs(1));
}
});
spawn(move || {
handle.join().unwrap();
let val = vec![
String::from("hello"),
String::from(" "),
String::from("world"),
];
for v in val {
tx1.send(v).unwrap();
sleep(Duration::from_secs(1));
}
});
for received in rx {
println!("Got: {}", received);
}
}
use std::sync::{ Mutex, Arc };
use std::thread::spawn;
fn main() {
let count = Arc::new(Mutex::new(0));
let mut handle_list = vec![];
for _ in 0..10 {
let counter = count.clone();
let handler = spawn(move || {
let mut m = counter.lock().unwrap();
*m += 1;
});
handle_list.push(handler);
}
for handle in handle_list {
handle.join().unwrap();
}
println!("Result: {}", *count.lock().unwrap());
}
基础知识
1. 阴影特性
这种构造是允许的,因为第一个
spaces
变量是字符串类型,第二个spaces
变量是一个全新的变量,碰巧与第一个变量同名,是一个数字类型。因此,阴影使我们不必想出不同的名称,例如spaces_str
和spaces_num
;相反,我们可以重用更简单的spaces
名称。但是,如果我们尝试使用mut
它,将会编译报错2. 数据类型
整数类型:
i8
u8
i16
u16
i32
u32
i64
u64
i128
u128
isize
usize
整数字面量:
98_222
0xff
0o77
0b1111_0000
u8
仅)b'A'
浮点类型
Rust 也有两种用于浮点数的原始类型,它们是带小数点的数字。Rust 的浮点类型是
f32
andf64
,它们的大小分别是 32 位和 64 位。默认类型是f64
因为在现代 CPU 上它的速度大致相同,f32
但精度更高。布尔类型: bool
字符类型: char
复合类型:元祖和数组
3. 函数
函数体中包含语句和表达式,语句是执行某些操作但不返回值的指令。表达式 求值为结果值,语句没有返回值,函数可以使用return进行返回,同时也可以隐式返回最后一个表达式
4. 控制流
所有权
1. 基本概念
所有程序都必须在运行时管理它们使用计算机内存的方式。某些语言具有垃圾收集功能,会在程序运行时不断寻找不再使用的内存;在其他语言中,程序员必须显式分配和释放内存。Rust 使用第三种方法:内存通过所有权系统管理,其中包含一组编译器在编译时检查的规则。没有任何所有权功能会在程序运行时减慢程序的运行速度。
2. 参考和借用
参考:不能针对参考的值进行修改
规则:
3. 切片类型
字符串切片是指向String对象中某个连续部分的引用
字符串字面量就是切片
结构体
结构体可以基于特定领域创建有意义的自定义类型。通过使用结构体,可以将相关联的数据组合起来,增强代码的可读性。
枚举与模式匹配
使用包、单元包及模块来管理复杂项目
1. 包与单元包
二进制单元包:src/bin 下添加的源文件都称之为二进制单元包, mian.rs 也算是二进制单元包
库单元包:
2. mod 模块系统
3. 用use关键字将路径导入作用域
src/lib.rs
Src/test_mod.rs
通用集合类型
1. 动态数组
2. 字符串
3. 哈希映射
错误处理
错误主要分为两类:可恢复错误和不可恢复错误,对于可恢复错误,一般需要将它们报告给用户并且再次尝试操作,对于不可恢复的错误,一般是程序bug
针对可恢复错误,提供错误的类型Result<T, E>,以及在程序出现不可恢复错误时中止运行的panic!宏
1. 不可恢复错误与panic!
调用panic!之后,程序会默认开始栈展开。这意味着Rust会沿着调用栈的反向顺序遍历所有调用函数,并依次清理这些函数中的数据。但是为了支持这种遍历和清理操作,我们需要在二进制中存储许多额外信息
除了展开之后,我们还可以选择立即终止程序,它会直接结束程序且不进行任何清理工作,程序使用的内存将由操作系统进行清除。可以通过在
Cargo.toml
文件中的[profile]
添加panic='abort'将panic的默认行为从展开切换为终止。针对panic的输出,可以通过设置
RUST_BACKTRACE=1
输出更加详情的堆栈信息2. 可恢复错误
3. 要不要手动使用panic!
一般来说是不需要使用
泛型、trait与生命周期
1. 泛型
2. trait:定义共享行为
3. 生命周期:看不太懂
编译器使用了三种规则来计算引用的声明周期,而返回值的声明周期被称为输出生命周期
eg:可以看文章详细了解 https://learnku.com/articles/44644
编写自动化测试
1. 编写简单的测试用例
2. 验证测试成功
3. 验证测试用例panic
4. 使用Result<T, E>编写测试用例
5. cli相关参数
通过--ignored运行被忽视的测试用例
6. 测试的组织结构
单元测试:小而专注,每次只单独测试一个模块或私有接口。
集成测试:完全位于代码库之外,和正常从外部调用代码库一样使用外部代码,只能访问公共接口,并且在一次测试中可能会联用多个模块。
单元测试在上述已经提了很多次,这里重点讲下集成测试,为了创建集成测试,你首先需要建立一个tests目录。Cargo会自动在这个目录下寻找集成测试文件。我们可以在这个目录下创建任意多个测试文件,Cargo在编译时会将每个文件都处理为一个独立的包。
实例项目
函数式语言特性:迭代器和闭包
1. 闭包
2. 迭代器
3. I/O项目优化
优化代码行数
4. 运行时性能
尽管迭代器是一种高层次的抽象,但它在编译后生成了与手写底层代码几乎一样的产物。迭代器是Rust语言中的一种零开销抽象(zero-cost abstraction),这个词意味着我们在使用这些抽象时不会引入额外的运行时开销
进一步认识Cargo及crates.io
1. 使用发布配置类定制构建
cargo-features
— Unstable, nightly-only features.[package]
— Defines a package.name
— The name of the package.version
— The version of the package.authors
— The authors of the package.edition
— The Rust edition.rust-version
— The minimal supported Rust version.description
— A description of the package.documentation
— URL of the package documentation.readme
— Path to the package's README file.homepage
— URL of the package homepage.repository
— URL of the package source repository.license
— The package license.license-file
— Path to the text of the license.keywords
— Keywords for the package.categories
— Categories of the package.workspace
— Path to the workspace for the package.build
— Path to the package build script.links
— Name of the native library the package links with.exclude
— Files to exclude when publishing.include
— Files to include when publishing.publish
— Can be used to prevent publishing the package.metadata
— Extra settings for external tools.default-run
— The default binary to run bycargo run
.autobins
— Disables binary auto discovery.autoexamples
— Disables example auto discovery.autotests
— Disables test auto discovery.autobenches
— Disables bench auto discovery.resolver
— Sets the dependency resolver to use.[lib\]
— Library target settings.[[bin\]]
— Binary target settings.[[example\]]
— Example target settings.[[test\]]
— Test target settings.[[bench\]]
— Benchmark target settings.[dependencies\]
— Package library dependencies.[dev-dependencies\]
— Dependencies for examples, tests, and benchmarks.[build-dependencies\]
— Dependencies for build scripts.[target\]
— Platform-specific dependencies.[badges\]
— Badges to display on a registry.[features\]
— Conditional compilation features.[patch\]
— Override dependencies.[replace\]
— Override dependencies (deprecated).[profile\]
— Compiler settings and optimizations.[workspace\]
— The workspace definition.2. 代码发布到crates.io
cargo doc
命令生成pub use
重新组织对外的公共API智能指针
智能指针,都拥有一片内存区域并允许用户对其进行操作。它们还拥有元数据(例如容量等),并提供额外的功能或保障(例如String会保障其中的数据必定是合法的UTF-8编码)
Ref和RefMut,可以通过RefCell访问,是一种可以在运行时而不是编译时执行借用规则的类型。
1. 使用Deref trait将只能指针视作常规引用
2. 借助Drop trait在清理时运行代码
3. 基于引用计数的智能指针Rc\<T>
需要这个指针的原因:在图数据结构中,多个边可能会指向相同的节点,而这个节点从概念上来讲就同时属于所有指向它的边。一个节点只要在任意指向它的边还存在时就不应该被清理掉(只能在单线程中使用)
4. RefCell\和内部可变性模式 (只能应用于单线程场景)
5. 联合使用Rc\ 和RefCell\结合使用
6. 内存泄露
在Rust中创建出循环引用并不是特别容易,但也绝非不可能。如果你的程序中存在RefCell包含Rc或其他联用了内部可变性与引用计数指针的情形,那么你就需要自行确保不会在代码中创建出循环引用;
无畏并发
1. 使用线程运行多端代码
首先看下多线程带来的问题:
2. 消息传递
通过使用
mpsc::channel
函数创建了一个新的通道。路径中的mpsc
是英文“multiple producer, single consumer
”(多个生产者,单个消费者)的缩写。简单来讲,Rust标准库中特定的实现方式使得通道可以拥有多个生产内容的发送端,但只能拥有一个消耗内容的接收端(和rust
的所有权保持一致)3.共享状态的并发
Mutex与Cell系列类型有着相似的功能,它同样提供了内部可变性。我们在第15章使用了RefCell来改变Rc中的内容,而本节按照同样的方式使用Mutex来改变Arc中的内容。
4. 使用Sync trait和Send trait针对并发进行扩展
Send trait
的类型才可以安全的在线程间转移所有权Sync trait
Rust的面向对象编程特性
针对多态属性,Rust选择使用trait对象来替代继承
实现trait 对象必须保证对象安全
模式匹配
是rust中一种用来匹配类型结构的特殊语法,将模式与match表达式或其他工具配合使用可以更好的控制程序的流
match分支
必须穷尽匹配值的所有可能性,通过 _ 可以匹配所有可能的值
if let 条件表达式
不会强制开发者穷尽值的所有可能性
while let 条件循环
反复执行同一个模式匹配直到出现失败的情况
for循环
let语句
Rust会将表达式与模式进行比较,并为所有找到的名称赋值
函数的参数
可失败性:模式匹配可以失败
let
语句及for
循环只可以接受不可失败模式if let
和match
和while let
条件循环可以接受可失败模式使用结构来分解值
使用匹配守卫
@绑定
@运算符允许我们在测试一个值是否匹配模式的同时创建存储该值的变量。
Message::Hello的id字段是否在区间3...7中。另外,我们还想要将这个字段中的值绑定到变量id_variable上,以便我们在随后的分支代码块中使用它
高级特性
// 待定
1. 函数宏
2. 属性宏
3. derive宏
相关资料
cargo 相关教程
debug预发验证通过
多商品分段名称没有设置入口