IO操作
- Read:用于从输入流读取字节数据
- WriteL:用于向输出流中写入数据,包含字节数据和 UTF-8 数据两种格式
读(输入)
- std::io::stdin 返回标准输入流的句柄
- read_line:不会读取空行
- unwrap:简化回复错误的处理
let mut in_words = String::new();
let result = std::io::stdin().read_line(&mut in_words).unwrap();
println!("输入的是{}", in_words);
println!("读取的字节数{}", result);
写入
- std::io::stdout() 返回标准输出流的句柄
- write 是标准输出流 stdout 句柄上的一个方法,用于标准输出流中写入字节流的内容,不会追加换行符
let result1 = std::io::stdout().write("hello world".as_bytes()).unwrap();
println!("写入的字节数{}", result1);
文件系统
Rust语言使用结构体File来描述/展现一个文件
所有对结构体File的操作方法都会返回一个Result枚举。
以下是一些常用的文件方法
| 模块 | 方法 | 说明 |
|---|---|---|
| std::fs::File | open() | 静态方法,以只读模式打开文件 |
| std::fs::File | create() | 静态方法,以可写模式打开文件。如果文件存在则清空旧内容 如果文件不存在则新建 |
| std::fs::remove_file | remove_file() | 从文件系统中删除某个文件 |
| std::fs::OpenOptions | append() | 设置文件模式为追加 |
| std::io::Writes | write_all() | 将buf中的所有内容写入输出流 |
| std::io::Read | read_to_string() | 读取所有内容转换为字符串后追加到buf中 |
闭包
- 闭包,可以在没有标注的情况下运行,可以移动和借用
- 引用 &T
- 可变 &mut
- 值 T
- 闭包是一个匿名函数
let add = |x: i32, y: i32| { x + y };
println!("{}", add(3, 4));
let num = 2;
let add2 = |x| {x + num};
println!("{}", add2(3))
Rust 多线程
主线程执行完后,子线程不再执行
thread::spawn(|| {
for i in 1..10 {
println!("子线程{}", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("主线程{}", i);
thread::sleep(Duration::from_millis(1));
}
等待子线程执行
let handler = thread::spawn(|| {
for i in 1..10 {
println!("子线程{}", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("主线程{}", i);
thread::sleep(Duration::from_millis(1));
}
handler.join().unwrap();
错误处理
panic!()抛出一个异常
使用 unwarp 抛出异常,和 expect 区别是,可以自定义报错的信息,接收一个 msg:&str
let output = is_even(3).unwrap();
println!("{:?}", output);
fn is_even(number: i32) -> Result<bool, String>{
return if number % 2 == 0 { Ok((true)) } else { Err(("错误".to_string())) };
}
模块
mod module_name {
fn function_name(){
}
}
// pub 关键字
pub mod module_name {
pub fn function_name(){
}
// 私有方法
fn function_name(){
}
// 使用模块
use 公开模块::函数名称
}
创建模块
cargo new --lib mylib
- lib
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
- toml
[package]
name = "module_test"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
mylib={ path = "../module_test/mylib/" }
- main
use ::mylib::*;
fn main() {
let num = add(1, 2);
println!("{}", num)
}
类型系统
let spend = 1;
let cost = spend as f64;
println!("{}", cost);
let x = 1u8;
let y = 2u16;
使用别名(驼峰)
type MyU64
let num: MyU64 = 5 as MyU64;
类型转换
From
From trait 允许一种类型定义 “怎么根据另一种类型生成自己”,因此它提供了一种类型转换的简单机制。在标准库中有无数 From 的实现,规定原生类型及其他常见类型的转换功能。
let s1 = "从0到Go语言微服务架构师";
let s2 = String::from(s1);
#[derive(Debug)]
struct MyNumber {
num: i32,
}
impl From<i32> for MyNumber {
fn from(item: i32) -> Self {
MyNumber { num: item }
}
}
fn main() {
let my_number = MyNumber { num: 1 };
println!("{:?}", my_number);
}
Into
Into trait 就是把 From trait 倒过来而已。也就是说,如果你为你的类型实现了 From,那么同时你也就免费获得了 Into。
使用 Into trait 通常要求指明要转换到的类型,因为编译器大多数时候不能推断它。不过考虑到我们免费获得了 Into,这点代价不值一提。
let spend = 3;
let my_spend: MyNumber = spend.into();
println!("{:?}", my_spend);
解析字符串
经常需要把字符串转成数字。完成这项工作的标准手段是用 parse 函数。
只要对目标类型实现了 FromStr trait,就可以用 parse 把字符串转换成目标类型。 标准库中已经给无数种类型实现了 FromStr。如果要转换到用户定义类型,只要手动实现 FromStr 就行。
let cost: i32 = "5".parse().unwrap();
println!("{}", cost);
match
解构指针和引用
对指针来说,解构(destructure)和解引用(dereference)要区分开,因为这两者的概念是不同的,和 C 那样的语言用法不一样。
- 解引用使用 *
- 解构使用 &、ref、和 ref mut
```rs
// 获得一个 `i32` 类型的引用。`&` 表示取引用。
let num = &100;
match num {
// 用 `&val` 这个模式去匹配 `num`
&val => println!("&val 是: {:?}", val),
}
// 如果不想用 `&`,需要在匹配前解引用。
match *num {
val => println!("val 是: {:?}", val),
}
// Rust 对这种情况提供了 `ref`。它更改了赋值行为,从而可以对具体值创建引用。
// 下面这行将得到一个引用。
let ref num3 = 66;
// 相应地,定义两个非引用的变量,通过 `ref` 和 `ref mut` 仍可取得其引用。
let num4 = 5;
let mut mut_num4 = 7;
// 使用 `ref` 关键字来创建引用。
// 下面的 r 是 `&i32` 类型,它像 `i32` 一样可以直接打印,因此用法上
// 似乎看不出什么区别。但读者可以把 `println!` 中的 `r` 改成 `*r`,仍然能
// 正常运行。前面例子中的 `println!` 里就不能是 `*val`,因为不能对整数解
// 引用。
match num4 {
ref r => println!("num4 r is: {:?}", r),
}
// 类似地使用 `ref mut`。
match mut_num4 {
ref mut m => {
// 已经获得了 `mut_value` 的引用,先要解引用,才能改变它的值。
*m += 10;
println!("`mut_value`: {:?}", m);
}
}
解构结构体
struct Study {
name: String,
target: String,
spend: u32,
}
fn main(){
let s = Study {
name: String::from("从0到Go语言微服务架构师"),
target: String::from("全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。"),
spend: 3,
};
let Study {
name: name,
target: target,
spend: spend,
} = s;
println!("name = {}, target = {}, spend = {} ", name, target, spend);
// name = 从0到Go语言微服务架构师, target = 全面掌握Go语言微服务落地,代码级一次性解决微服务和分布式系统。, spend = 3
let s2 = Study {
name: String::from("《Go语言极简一本通》"),
target: String::from("学习Go语言,并且完成一个单体服务。"),
spend: 5,
};
// 也可以忽略某些变量
let Study { name, .. } = s2;
println!("name = {}", name);
//name = 《Go语言极简一本通》
}
async和await
[dependencies]
async-std = {version = "1.12.0", features = ["attributes"]}
多线程提高执行效率
use async_std::task::{sleep, spawn};
use std::time::Duration;
async fn do3() {
for i in 1..=5 {
println!("do3 {}", i);
sleep(Duration::from_millis(500)).await;
}
}
async fn do4() {
for i in 1..=5 {
println!("do4 {}", i);
sleep(Duration::from_millis(1000)).await;
}
}
#[async_std::main]
async fn main() {
let do3_async = spawn(do3());
do4().await;
do3_async.await;
}
async 关键字的作用
- 可以在函数体内使用.await 语法。
- 它修改了函数的返回类型。
async fn 函数名称() -> 返回值类型 实际上返回的是 impl std::future::Future<Output=返回值类型> - 自动将结果值封装进一个新的 Future 对象。
async fn lesson() -> String {
String::from("lesson")
}
async fn join_lesson() -> impl Future<Output = String> {
async {
let lesson = lesson().await;
"lesson".to_string() + &lesson
}
}
async fn join_lesson2() -> impl Future<Output = String> {
let r = |x: String| async move {
let y: String = join_lesson().await.await;
y + &*x
};
r(String::from(":12131312"))
}
...
let result = block_on(join_lesson2()).await;
println!("{}", result);