Rust
文章目录
- Rust
- 开发环境搭建
- 在线模式
- 离线模式
- 引入自定义第三方库
- 通用编程概念
- Hello
- 注释
- 印屏
- Display
- 变量
- 变量可变性
- 不可变变量与常量
- 变量冻结
- 延迟绑定
- 变量隐藏
- 数据类型
- 基本数据类型
- 类型别名
- 简单类型转换
- From和into
- String
- Array
- Tuple
- Struct
- Tuple Struct
- 函数与表达式
- 条件语句
- 循环语句
- 所有权
- 内存位置
- 引用位置
- 字符串位置
- 默认分配位置
- 所有权转移
- 引用与借用
- 可变引用
- 悬垂引用(Dangling References)
- 裸指针
- 切片(Slice)
- 引用生命周期
- &、ref、*
- 自动解引用
- 模式匹配
- 匹配数字
- 枚举类型
- C Like
- Rust Style
- Option
- if let
- 错误处理
- panic!
- Result
- 错误判断
- 错误类型
- 简化Result展开
- 传播错误
- 泛型与特性
- 实现(Implementation)
- 特性(Trait)
- 特性组合
- 运算符重载
- 特性实现重叠
- 泛型(Generic)
- 模拟重载(Overload)
- 多态
- Collection
- Vector
- HashMap
- IO
- 命令行
- 命令行参数
- 命令行输入
- 读取环境变量
- 读写文件
- 文件写入
- 文件读取
- 函数式编程
- Closure
- Lambda表达式
- 所有权捕获
- Iterator
- 消费迭代器
- 自定义迭代器
- 智能指针
- 指针类型
- Box
- Rc
- Cell&RefCell
- Weak
- 递归类型
- Deref
- Drop
- Module
- 单文件
- 多文件
- Macro
- unsafe
- Thread
- join
- channel
- Mutex & Arc
- Sync & Send
- Socket
- Tcp
- UdpBroadcast
开发环境搭建
- :Windows下确保已完成MinGW-w64(推荐使用MingW-W64-builds)的安装;
在线模式
- :下载Rustup安装程序;
- :打开命令窗口输入以下命令:
@REM SET CARGO_HOME=
@REM SET RUSTUP_HOME=
SET RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
SET RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
.\rustup-init.exe
- :提示缺少Microsoft C++ build tools,回车继续;
If you will be targeting the GNU ABI or otherwise know what you are
doing then it is fine to continue installation without the build
tools, but otherwise, install the C++ build tools before proceeding.
Continue? (Y/n) Y
- :自定义安装信息:
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>2
- :配置default host triple,其它选择直接回车使用默认:
Default host triple?
x86_64-pc-windows-gnu
最终配置如下:
default host triple: x86_64-pc-windows-gnu
default toolchain: stable
profile: default
modify PATH variable: yes
- :继续安装等待安装完成:
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1
离线模式
- x86_64-windows:
x86_64-pc-windows-gnu
- x86_64-linux:
x86_64-unknown-linux-gnu
- aarch:
aarch64-unknown-linux-gnu
- :下载Source Code
- :下载rustfmt用于自动格式化代码;
修改配置:
# Linux
vim ~/.cargo/config.toml
REM Windows
notepad %USERPROFILE%\.cargo\config.toml
引入自定义第三方库
Cargo.toml
[dependencies]
libname = { path = "..." }
通用编程概念
Hello
fn main() {
println!("hello world!");
}
注释
// Line comments which go to the end of the line.
/* Block comments which go to the closing delimiter. */
// Doc comments which are parsed into HTML library documentation:
/// Generate library docs for the following item.
//! Generate library docs for the enclosing item.
印屏
// 一行
print!("line\n");
println!("line");
// 输出{}
println!("{{}}");
// 输出\
println!("\\");
说明 | |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)]
#[derive(Debug)] // This make it printable by {:?}.
struct Student {
id: i64,
name: String,
age: i32,
gender: bool,
}
let student = Student {
id: 9955845621,
name: String::from("Peter"),
age: 0x1a,
gender: false,
};
println!("Hello {}!", student.name);
println!("{0}'s name is {0}.", student.name);
println!("{yourname}'s name is {yourname}.", yourname = student.name);
println!("{0}'s id is {1}.", student.name, student.id);
println!("{0}'s id is {1:e}.", student.name, student.id);
println!("{0}'s id is {1:E}.", student.name, student.id);
println!("{0} is {1} years old.", student.name, student.age);
println!("{0} is 0b{1:b} years old.", student.name, student.age);
println!("{0} is 0o{1:o} years old.", student.name, student.age);
println!("{0} is 0x{1:x} years old.", student.name, student.age);
println!("{0} is 0X{1:X} years old.", student.name, student.age);
println!("Student Pointer @{:p}!", &student);
println!("Student Debug {:?}!", student);
Display
use std::fmt::{self, Display, Formatter};
struct Point {
x: f32,
y: f32,
}
// 自定义结构体打印方式
impl Display for Point {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Display for Point(x={}, y={})", self.x, self.y)
}
}
let p = Point { x: 0.1, y: 0.2 };
println!("{}", p);
// Display for Point(x=0.1, y=0.2)
变量
变量可变性
let x = 5;
println!("The value of x is: {}", x);
x = 6; // Error: cannot assign twice to immutable variable
println!("The value of x is: {}", x);
let mut x = 5;
println!("The value of x is: {}", x);
x = 6; // It's ok!
println!("The value of x is: {}", x);
不可变变量与常量
- 声明常量时,必须注明值的类型。
- 常量可以在任何作用域声明,包括全局作用域。
- 常量不能作为函数调用的结果。
const PI: f32 = 3.1415926; // It's ok
const PI_2: f32 = PI / 2.0; // It's ok
fn get_pi() -> f32 { 3.1415926 }
let pi = get_pi(); // It's ok
const PI: f32 = get_pi(); // Error: cannot call non-const fn in constants
变量冻结
let mut freezing = 666;
println!("freezing = {}", freezing);
{
#[allow(unused_variables)]
let freezing = freezing;
freezing = 555; //Error: cannot assign twice to immutable variable
}
println!("freezing = {}", freezing);
freezing = 999;
println!("freezing = {}", freezing);
延迟绑定
let x;
x = 5; // It's ok!
println!("The value of x is: {}", x);
x = 6; // Error: cannot assign twice to immutable variable
println!("The value of x is: {}", x);
变量隐藏
// Shadowing
let x = 5;
println!("The address of x is: @{:p}", &x);
let x = x + 1;
println!("The address of x is: @{:p}", &x);
let x = x * 2;
println!("The address of x is: @{:p}", &x);
// The address of x is: @0xa7faac
// The address of x is: @0xa7fafc
// The address of x is: @0xa7fb4c
let mut x = 5;
println!("The address of x is: @{:p}", &x);
x = x + 1;
println!("The address of x is: @{:p}", &x);
x = x * 2;
println!("The address of x is: @{:p}", &x);
// The address of x is: @0xa7faac
// The address of x is: @0xa7faac
// The address of x is: @0xa7faac
数据类型
基本数据类型
let _: i8;
let _: u8 = b'A';
let _: u8 = 0b1111_0000; // 下划线起注释作用
let _: i16;
let _: u16;
let _: i32;
let _: u32;
let _: i64 = 98_222; // 下划线起注释作用
let _: u64;
let _: i128;
let _: u128;
let _: isize; // 取决于操作系统位数
let _: usize; // 取决于操作系统位数
let _: f32;
let _: f64;
let _: char;
let _: bool; // true | false
println!("size(char) = {}", std::mem::size_of_val(&'A'));
println!("size(bool) = {}", std::mem::size_of_val(&true));
// size(char) = 4
// size(bool) = 1
类型别名
#[allow(non_camel_case_types)]
type uint64_t = u64;
#[allow(non_camel_case_types)]
type uint32_t = u32;
let x = 0 as uint32_t;
let y = 0 as uint64_t;
println!("size(uint32_t) = {}", std::mem::size_of_val(&x));
println!("size(uint64_t) = {}", std::mem::size_of_val(&y));
// size(uint32_t) = 4
// size(uint64_t) = 8
简单类型转换
const NPI: f64 = -3.1415926535897f64; // Literal
println!("NPI as f64 = {}", NPI);
println!("NPI as f32 = {}", NPI as f32);
println!("NPI as i32 = {}", NPI as i32);
println!("NPI as u32 = {}", NPI as u32);
// NPI as f64 = -3.1415926535897
// NPI as f32 = -3.1415927
// NPI as i32 = -3
// NPI as u32 = 0
From和into
自定义复合类型的转换方式。
#[allow(dead_code)]
#[derive(Debug)]
struct Number {
value: i32,
}
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
// let num = Number::from(1111);
// ↑↓ 等效
let num: Number = 1111.into(); // 必须指定类型
println!("num = {:?}", num);
String
let s1: &str = "hello";
let s2: &str = s1;
println!("s1 = {:p}", s1);
println!("s2 = {:p}", s2);
// s1 = 0x4ba030
// s2 = 0x4ba030
let s11: String = String::from(s1);
let s12: String = String::from(s1);
println!("s11 = {:p}", &s11);
println!("s12 = {:p}", &s12);
// s11 = 0xa8fac8
// s12 = 0xa8fae0
Array
let arr: [i32; 5] = [1, 2, 3, 4, 5];
println!("len = {}", arr.len());
println!("arr = {:?}", arr);
println!("arr[0] = {}", &arr[0]);
// len = 5
// arr = [1, 2, 3, 4, 5]
// arr[0] = 1
let arr: [i32; 10] = [0; 10]; // 10个0
println!("len = {}", arr.len());
println!("arr = {:?}", arr);
println!("arr[0] = {}", &arr[0]);
// len = 10
// arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// arr[0] = 0
Array
长度固定,Vector
可动态扩容。
let mut v = vec![0, 1, 2];
v.push(3);
let a = [0, 1, 2];
// a.push(3); // Error: method not found
println!("{}, v = {:?}", v.len(), v);
println!("{}, a = {:?}", a.len(), a);
// 4, v = [0, 1, 2, 3]
// 3, a = [0, 1, 2]
// [v -> a]
// 可通过迭代拷贝实现,但长度必须事先确定
// [a -> v]
// let v2: Vec<i32> = a.into();
// ↑↓ 等效
// let v2 = Vec::from(a);
// ↑↓ 等效
let v2 = a.to_vec();
println!("{}, v2 = {:?}", v2.len(), v2);
// 3, v2 = [0, 1, 2]
Tuple
let tup: (i32, f32, u8) = (500, 6.4, 1);
println!("tup = {:?}", tup);
// tup = (500, 6.4, 1)
println!("The value of x is: {}", tup.0);
// The value of x is: 500
// Destructure
let (_, y, _) = tup;
println!("The value of y is: {}", y);
// The value of y is: 6.4
Struct
#[allow(dead_code)]
#[derive(Debug)]
struct Point {
x: f32,
y: f32,
}
// 一般创建
let point1 = Point { x: 10.3, y: 0.4 };
// 复用旧结构体
let point2 = Point { y: 6.18, ..point1 };
// 同名略写
let x = 32f32;
let y = 45f32;
let point3 = Point { x, y };
println!("point1 = {:?}", point1);
println!("point2 = {:?}", point2);
println!("point3 = {:?}", point3);
// point1 = Point { x: 10.3, y: 0.4 }
// point2 = Point { x: 10.3, y: 6.18 }
// point3 = Point { x: 32.0, y: 45.0 }
Tuple Struct
#[derive(Debug)]
struct Color(u8, u8, u8);
let black = Color(0, 0, 0);
println!("black = {:?}", black);
println!("black.0 = {}", black.0);
// black = Color(0, 0, 0)
// black.0 = 0
函数与表达式
// 表达式
let x = { let y = 0; y + 1 };
println!("The value of x is: {}", x);
// The value of x is: 1
// 语句
let x = { let y = 0; y + 1; };
// println!("The value of x is: {}", x);
// Error: `()` cannot be formatted with the default formatter
// 一般函数
fn add(a: i32, b: i32) -> i32 {
return a + b;
}
println!("add(1, 2) = {}", add(1, 2));
// 省略return
fn mul(a: i32, b: i32) -> i32 {
a * b
}
println!("mul(2, 3) = {}", mul(2, 3));
条件语句
- 条件必须是布尔值。
- 大括号不可省。
if false {
} else if false {
} else {
}
// 三元表达式
let r = if true { 1 } else { 0 };
println!("r = {}", r);
循环语句
while false {
continue;
}
// 默认无限循环
loop {
break;
}
// 遍历范围 [1, 3)
for i in 1..3 {
println!("{}", i);
}
// 遍历范围 [1, 3]
for i in 1..=3 {
println!("{}", i);
}
// 遍历列表
let a = [10, 20, 30, 40, 50];
for i in 0..5 {
println!("a[{}] = {}", i, a[i]);
}
// 遍历对象列表
#[derive(Debug)]
struct Color {
r: u8,
g: u8,
b: u8,
}
let arr = [
Color { r: 128, g: 255, b: 90 },
Color { r: 0, g: 3, b: 254 },
Color { r: 0, g: 0, b: 0 },
];
for color in arr.iter() {
println!("{:?}", color);
}
所有权
内存位置
引用位置
let x = 6;
let r = &x;
+–––––––+
│ │
+–––+–V–+–––+–│–+–––+
stack frame │ │ 6 │ │ • │ │
+–––+–––+–––+–––+–––+
[–––] [–––]
x r
字符串位置
let s: &str = "Rust";
s
[–––––––]
+–––+–––+–––+
stack frame │ • │ 4 │ │
+–│–+–––+–––+
│
│
│
preallocated +–V–+–––+–––+–––+
read-only │ R │ u │ s │ t │
memory +–––+–––+–––+–––+
let s: String = String::from("Rust");
let l: &str = &s[2..];
let r: &String = &s;
println!("The pointer of s is: {:p}", s.as_bytes()); // heap
println!("The pointer of l is: {:p}", l); // heap
// The pointer of s is: 0xb67990
// The pointer of l is: 0xb67992
println!("The pointer of &s is: {:p}", &s); // stack
println!("The pointer of &l is: {:p}", &l); // stack
println!("The pointer of r is: {:p}", r); // stack
println!("The pointer of &r is: {:p}", &r); // stack
// The pointer of &s is: 0xa8f9a8
// The pointer of &l is: 0xa8f9c0
// The pointer of r is: 0xa8f9a8
// The pointer of &r is: 0xa8f9d8
+-------------------–––––-––+
| s l |
[–|–––––––––] [–––––––] |
+–V–+–––+–––+–––+–––+–––+–––+–│–+–––+
stack frame │ • │ 4 │ 4 │ │ • │ 2 │ │ • │ │
+–│–+–––+–––+–––+–│–+–––+–––+–––+–––+
│ │ [---]
│ +-------+ r
│ │
│ │
│ [–|–––––]
+–V–+–––+–V–+–––+
heap │ R │ u │ s │ t │
+–––+–––+–––+–––+
默认分配位置
默认分配在栈上的内容:整数类型、浮点数类型、布尔类型、仅包含以上类型的元组。
// 实现了Copy trait: 储存在栈上
let x: i32 = 12;
let y = x.clone(); // 值拷贝
let z = x; // 值拷贝(等效于上一条语句)
println!("The value of z is: {}", z); // It's ok
println!("The value of y is: {}", y); // It's ok
println!("The value of x is: {}", x); // It's ok
// 实现了Drop trait: 储存在堆上
let s1: String = String::from("sss");
let s2 = s1.clone(); // 深拷贝
let s3 = s1; // 移动(之后s1不再可用)
println!("The value of s3 is: {}", s3); // It's ok
println!("The value of s2 is: {}", s2); // It's ok
println!("The value of s1 is: {}", s1); // Error: value borrowed here after move
所有权转移
- 每个值都有且仅有一个所有者。
- 当所有者离开作用域时,变量会被回收。
fn makes_copy(xx: i32) {
println!("The value of xx is: {}", xx);
}
fn takes_reference(sr: &String) {
println!("The value of sr is: {}", sr);
}
fn takes_ownership(ss: String) {
println!("The value of ss is: {}", ss);
}
let x = 32;
let s = String::from("hello");
println!("The value of x is: {}", x);
println!("The value of s is: {}", s);
makes_copy(x); // 值拷贝
println!("The value of x is: {}", x);
takes_reference(&s); // 引用浅拷贝
println!("The value of s is: {}", s);
takes_ownership(s); // 所有权转移(移动)
println!("The value of s is: {}", s); // value borrowed here after move
引用与借用
获取值的引用,但不获取其所有权称为借用(borrowing)。
fn calculate_length(s: &String) -> usize {
s.len()
}
let s = String::from("hello");
let l = calculate_length(&s);
println!("length = {}", l);
// length = 5
可变引用
fn push_world(rs: &mut String) {
rs.push_str(" world");
}
let mut s = String::from("hello");
push_world(&mut s);
println!("{}", s);
可变引用不能被连续借用:
let mut s = String::from("hello");
let r1 = &mut s; // It's ok
let r2 = &mut s; // Error: cannot borrow `s` as mutable more than once at a time
println!("{}", r1);
println!("{}", r2);
不能在混合借用可变与不可变引用:
let mut s = String::from("hello");
let r1 = &s; // It's ok
let r2 = &s; // It's ok
let r3 = &mut s; // Error: cannot borrow `s` as mutable because it is also borrowed as immutable
println!("{}", r1);
println!("{}", r2);
println!("{}", r3);
悬垂引用(Dangling References)
编译器可以确保数据引用不离开其作用域。
fn dangle() -> &String { // Error: expected named lifetime parameter
let s = String::from("hello");
&s // 悬垂指针(dangling pointer)
}
裸指针
- 允许忽略借用规则,可以同时拥有不可变和可变的指针,或多个指向相同位置的可变指针
- 不保证指向有效的内存
- 允许为空
- 不能实现任何自动清理功能
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
// 仅能在 unsafe 中解裸指针
println!("{}", *r1);
println!("{}", *r2);
}
切片(Slice)
切片是一种不完整的引用,类似于SQL中的视图。
let s = "0123456789A";
let l = s.len();
let all_view: &str = &s[..];
let get_left_3 = &s[..3];
let del_left_3 = &s[3..];
let get_3_6 = &s[3..6];
let get_right_3 = &s[l - 3..];
let del_right_3 = &s[..l - 3];
println!("all_view = {}", all_view);
println!("get_left_3 = {}", get_left_3);
println!("del_left_3 = {}", del_left_3);
println!("get_3_6 = {}", get_3_6);
println!("get_right_3 = {}", get_right_3);
println!("del_right_3 = {}", del_right_3);
// all_view = 0123456789A
// get_left_3 = 012
// del_left_3 = 3456789A
// get_3_6 = 345
// get_right_3 = 89A
// del_right_3 = 01234567
引用生命周期
{
let a: &i32; // -------+-- 'a
// |
{ // |
let b: i32 = 5; // -+-----+-- 'b
a = &b; // | |
} // -+ |
// |
println!("a: {}", a); // |
} // -------+
// Error: borrowed value does not live long enough
// lifetime(b) < lifetime(a)
{
let b: i32 = 5; // -----+-- 'b
// |
let a: &i32 = &b; // --+--+-- 'a
// | |
println!("a: {}", a); // | |
// --+ |
} // -----+
// lifetime(b) > lifetime(a)
生命周期注解语法:
&i32 // a reference
&'a i32 // a reference with an explicit lifetime
&'a mut i32 // a mutable reference with an explicit lifetime
// a : 拥有确切的生命周期
// x,y : 需要与 a 的生命周期一样久
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
&、ref、*
let mut val: i32 = 111;
let a = &mut val;
*a = 222;
println!("{}", val);
// 222
let ref mut b = val;
*b = 333;
println!("{}", val);
// 333
// 仅能用 & 的情况
fn only_and() {
fn test(val: &mut i32) {
*val = 999;
}
let mut x: i32 = 0;
test(&mut x);
println!("x = {}", x);
// 999
}
// 仅能用 ref 的情况
fn only_ref() {
let s = Some(String::from("Hello!"));
// match &s { // 此处借用s
// Some(r) => println!("r = {}", r),
// None => println!("None"),
// }
// ↑↓ 等价
match s {
// 此处没有机会声明变量类型
// 只能用 ref 表示变量 r 是个指针。
Some(ref r) => println!("r = {}", r),
None => println!("None"),
}
println!("s = {}", s.unwrap());
}
自动解引用
let a: &i32 = &123;
let b: &&i32 = &a;
let c: &&&i32 = &b;
println!("a = {}, b = {}, c = {}", a, b, c);
println!("*a = {}, **b = {}, ***c = {}", *a, **b, ***c);
// a = 123, b = 123, c = 123
// *a = 123, **b = 123, ***c = 123
模式匹配
匹配数字
fn get_number_name(num: i32) {
print!("{}, ", num);
match num {
1 => println!("One"),
2 | 3 => println!("Two | Three"),
4..=7 => println!("Four ~ Seven"),
_ => {
println!("Unknow");
}
}
}
for i in 1..=8 {
get_number_name(i);
}
// 1, One
// 2, Two | Three
// 3, Two | Three
// 4, Four ~ Seven
// 5, Four ~ Seven
// 6, Four ~ Seven
// 7, Four ~ Seven
// 8, Unknow
枚举类型
C Like
enum Fruit {
Apple,
Banana = 3,
Watermelon,
}
println!("Fruit::Apple is {}", Fruit::Apple as i32);
// use Fruit::Banana;
use Fruit::{Banana, Watermelon};
// use Fruit::*;
println!("Fruit::Banana is {}", Banana as i32);
println!("Fruit::Watermelon is {}", Watermelon as i32);
// Fruit::Apple is 0
// Fruit::Banana is 3
// Fruit::Watermelon is 4
Rust Style
#[derive(Debug)]
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
print!("Coin({:?}) = ", coin);
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
println!("{}", value_in_cents(Coin::Penny));
println!("{}", value_in_cents(Coin::Nickel));
println!("{}", value_in_cents(Coin::Dime));
println!("{}", value_in_cents(Coin::Quarter));
// Coin(Penny) = 1
// Coin(Nickel) = 5
// Coin(Dime) = 10
// Coin(Quarter) = 25
#[derive(Debug)]
enum WebEvent {
PageLoad,
PageUnload,
KeyPress(char),
Paste(String),
Click { x: i64, y: i64 },
}
fn inspect(event: WebEvent) {
print!("event({:?}) = ", event);
match event {
WebEvent::PageLoad => println!("page loaded"),
WebEvent::PageUnload => println!("page unloaded"),
WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
WebEvent::Paste(s) => println!("pasted \"{}\".", s),
WebEvent::Click { x, y } => {
println!("clicked at x={}, y={}.", x, y);
}
}
}
inspect(WebEvent::PageLoad);
inspect(WebEvent::KeyPress('x'));
inspect(WebEvent::Paste("my text".to_owned()));
inspect(WebEvent::Click { x: 20, y: 80 });
inspect(WebEvent::PageUnload);
// event(PageLoad) = page loaded
// event(KeyPress('x')) = pressed 'x'.
// event(Paste("my text")) = pasted "my text".
// event(Click { x: 20, y: 80 }) = clicked at x=20, y=80.
// event(PageUnload) = page unloaded
Option
Rust并没有空值,取而代之的是Option<T>
,其被定义为:
enum Option<T> {
Some(T),
None,
}
如果使用None
而不是Some
,需要告诉RustOption<T>
是什么类型的。
let num = Some(5);
let val = match num {
Some(i) => i,
None => -1,
};
let absent: Option<i32> = None;
println!("is_some = {}, val = {}", num.is_some(), val);
println!("is_none = {}", absent.is_none());
// is_some = true, val = 5
// is_none = true
if let
let num = Some(5);
if let Some(i) = num {
println!("If matched `{}`!", i);
}
// If matched `5`!
while let Some(i) = num {
println!("While matched `{}`!", i);
break;
}
// While matched `5`!
#[allow(dead_code)]
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
let coin = Coin::Penny;
if let Coin::Penny = coin {
println!("A Penny!");
}
// A Penny!
错误处理
错误分类:
- 可恢复错误(recoverable):
Result<T, E>
- 不可恢复错误(unrecoverable):
panic!
panic!
程序会打印出一个错误信息,展开并清理栈数据,然后接着退出。
pub fn main() {
// 手动造成一个 panic
panic!("crash and burn");
// process didn't exit successfully
}
pub fn main() {
// panic 由其它库抛出
let v = vec![1, 2, 3];
v[99];
// process didn't exit successfully
}
Result
Result
被定义为:
enum Result<T, E> {
Ok(T),
Err(E),
}
错误判断
use std::io::Result;
use std::fs::File;
const FILE_PATH: &str = "test.txt";
let fr: Result<File> = File::open(FILE_PATH);
if fr.is_ok() {
println!("Opened");
}
if fr.is_err() {
println!("Error is {:?}", fr.err().unwrap());
// Error is Os { code: 2, kind: NotFound, message: "系统找不到指定的文件。" }
}
错误类型
use std::io::{Result, ErrorKind, Write};
use std::fs::File;
const FILE_PATH: &str = "test.txt";
let f: Result<File> = File::open(FILE_PATH);
#[allow(unused_variables)]
let f: File = match f {
Ok(f) => f,
// match guard: 这个条件必须为真才能使分支的代码被执行
Err(ref e) if e.kind() == ErrorKind::NotFound => {
// 创建一个文件
match File::create(FILE_PATH) {
Ok(mut fc) => {
fc.write("Hello Test!".as_bytes()).unwrap();
fc
}
Err(ec) => {
panic!("Error is {:?}", ec)
}
}
}
Err(e) => {
panic!("Error is {:?}", e)
}
};
简化Result展开
unwrap
和expect
可简化match Result<T>
。
use std::io::{Result, ErrorKind};
use std::fs::File;
const FILE_PATH: &str = "test.txt";
let f: Result<File> = File::open(FILE_PATH);
let f: File = match f {
Ok(f) => f,
Err(e) => panic!("{}", e),
};
// ↑↓
let f: File = File::open(FILE_PATH).unwrap();
// ↑↓
let f: File = File::open(FILE_PATH).expect("Error"); // 自定义panic信息
传播错误
选择让调用者知道这个错误并决定该如何处理,这被称为传播(propagating)错误。
use std::io::{Result, Read};
use std::fs::File;
const FILE_PATH: &str = "hello.txt";
fn propagating() -> Result<String> {
let mut file = match File::open(FILE_PATH) {
Ok(f) => f,
Err(e) => return Err(e), // 函数返回
};
let mut buff = String::new();
match file.read_to_string(&mut buff) {
Ok(_) => Ok(buff), // 函数返回
Err(e) => Err(e), // 函数返回
}
}
let t = propagating();
if t.is_ok() {
let s = t.unwrap();
println!("{}", s);
} else {
let e = t.err().unwrap();
println!("{:?}", e);
}
// 传播简写
fn propagating() -> Result<String> {
let mut buff = String::new();
let mut file = File::open(FILE_PATH)?; // 返回T || 返回 Err(e)
file.read_to_string(&mut buff)?; // 返回T || 返回 Err(e)
Ok(buff)
}
// 传播简简写
fn propagating() -> Result<String> {
let mut buff = String::new();
File::open(FILE_PATH)?.read_to_string(&mut buff)?;
Ok(buff)
}
泛型与特性
实现(Implementation)
#[allow(dead_code)]
#[derive(Debug)]
struct Point {
x: f32,
y: f32,
}
// 在结构体域上实现方法
impl Point {
// 修改当前实例的对象
fn add_to_point(&mut self, p2: &Point) {
self.x += p2.x;
self.y += p2.y;
}
// 获取实例的所有权,生成新对象
fn add_new_point(self, p2: &Point) -> Point {
Point { x: self.x + p2.x, y: self.y + p2.y }
}
// 关联函数:不含self
fn from_xy(x: f32, y: f32) -> Point {
Point { x, y }
}
}
let p1 = Point::from_xy(2.0, 3.0);
let mut p2 = Point { x: 23.0, y: 22.0 };
(&mut p2).add_to_point(&p1); // 手动解引用
p2.add_to_point(&p1); // 自动解引用,
println!("p2 = {:?}", p2);
// p2 = Point { x: 27.0, y: 28.0 }
let p3 = p2.add_new_point(&p1);
// println!("p2 = {:?}", p2); // Error: value borrowed here after move
println!("p3 = {:?}", p3);
// p3 = Point { x: 29.0, y: 31.0 }
特性(Trait)
类似于Java中的接口。
// interface-like
trait Walkable {
fn walk(&self);
fn echo(&self) { // 默认实现
println!("echo!");
}
}
// class-like
struct People {}
impl Walkable for People {
fn walk(&self) {
println!("People walk!");
}
fn echo(&self) {
println!("People echo!");
}
}
// class-like
struct Animal {}
impl Walkable for Animal {
fn walk(&self) {
println!("Animal walk!");
}
}
let p = People{};
let a = Animal{};
p.walk();
p.echo();
a.walk();
a.echo();
// People walk!
// People echo!
// Animal walk!
// echo!
特性组合
trait Walkable {
fn walk(&self);
}
trait Runnable {
fn run(&self);
}
// 组合
trait Walk2Runnable: Walkable + Runnable {
fn walk_2_run(&self);
}
struct People {}
impl Walkable for People {
fn walk(&self) {
print!("walk");
}
}
impl Runnable for People {
fn run(&self) {
print!("run");
}
}
// 如果要实现Walk2Runnable,必须实现Walkable和Runnable
impl Walk2Runnable for People {
fn walk_2_run(&self) {
self.walk();
print!("->");
self.run();
}
}
let p = People{};
p.walk_2_run();
// walk->run
运算符重载
use std::ops::Add;
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
let p = Point { x: 1, y: 0 } + Point { x: 2, y: 3 };
println!("{:?}", p);
特性实现重叠
trait Pilot {
fn fly(&self);
}
trait Wizard {
fn fly(&self);
}
struct Human;
impl Pilot for Human {
fn fly(&self) {
println!("This is your captain speaking.");
}
}
impl Wizard for Human {
fn fly(&self) {
println!("Up!");
}
}
let person = Human;
Pilot::fly(&person);
Wizard::fly(&person);
person.fly(); // Error: multiple applicable items in scope
泛型(Generic)
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
fn y(&self) -> &T {
&self.y
}
}
let p = Point { x: 5, y: 10 };
println!("p.x = {}, p.y = {}", p.x(), p.y());
enum Boolean<T, F> {
True(T),
False(F),
}
trait bound:只为实现了特定trait的类型的结构实现方法。
// 方式一
fn largest<T: PartialOrd + Copy>(a: &[T]) -> T {
let mut n = a[0];
for &i in a.iter() {
if i > n { n = i; }
}
n
}
// 方式二
fn largest<T>(a: &[T]) -> T where T: PartialOrd + Copy {
let mut n = a[0];
for &i in a.iter() {
if i > n { n = i; }
}
n
}
let n_arr = vec![34, 50, 25, 100, 65];
let c_arr = vec!['y', 'm', 'a', 'q'];
let result = largest(&n_arr);
println!("The largest number is {}", result);
let result = largest(&c_arr);
println!("The largest char is {}", result);
模拟重载(Overload)
Rust中trait From
被定义为:
pub trait From<T>: Sized {
fn from(value: T) -> Self;
}
String
对其的两个实现为:
impl From<char> for String {
fn from(c: char) -> Self {
c.to_string()
}
}
impl From<&str> for String {
fn from(s: &str) -> String {
s.to_owned()
}
}
通过泛型和特性实现的重载功能:
let s1 = String::from('A');
let s2 = String::from("A");
多态
泛型为单态化处理,所产生的代码进行静态分发(static dispatch),这与**动态分发(dynamic dispatch)**相对。dyn
关键字表示具体类型已被擦去,一个dyn引用包含两个指针:
- 指向数据
- 指向方法调用名称与函数指针的映射
// Draw特性
pub trait Draw {
fn draw(&self);
}
// 屏幕上是可Draw组件
pub struct Screen {
// 类型擦除
pub components: Vec<Box<dyn Draw>>,
}
impl Screen {
// 屏幕运行时,绘制所有可Draw组件
pub fn run(&self) {
for component in self.components.iter() {
// 基于泛型和Trait实现的多态。
component.draw();
}
}
}
// Button可Draw
pub struct Button {
/* ... */
}
impl Draw for Button {
fn draw(&self) { println!("draw Button") }
}
// Label可Draw
pub struct Label {
/* ... */
}
impl Draw for Label {
fn draw(&self) { println!("draw Label") }
}
let screen = Screen {
components: vec![Box::new(Label {}), Box::new(Button {})],
};
screen.run();
Collection
use std::vec;
use std::collections::{
VecDeque,
LinkedList,
HashMap,
HashSet,
BTreeMap,
BTreeSet,
BinaryHeap,
};
Vector
let mut vec_u8: Vec<u8> = Vec::new();
vec_u8.push(77u8);
vec_u8.push(99u8);
println!("vec_u8 = {:?}", vec_u8);
for i in &vec_u8 {
println!("{}", i);
}
// 容器自动推断
let mut vec_auto = Vec::new();
vec_auto.push(66u8);
vec_auto.push(88u8);
for i in &mut vec_auto {
*i -= 2;
}
println!("vec_auto = {:?}", vec_auto);
HashMap
use std::collections::HashMap;
let mut kv1 = HashMap::new();
kv1.insert("Blue", 10);
kv1.entry("Yellow").or_insert(50);
kv1.entry("Blue").or_insert(50);
println!("{:?}", kv1);
let mut kv2: HashMap<i32, String> = HashMap::new();
kv2.insert(0, String::from("A"));
kv2.insert(1, String::from("B"));
kv2.insert(2, String::from("C"));
println!("{:?}", kv2);
IO
命令行
命令行参数
use std::env;
let args: Vec<String> = env::args().collect();
println!("len = {}", args.len());
println!("args = {:?}", args);
println!("args[0] = {}", &args[0]);
命令行输入
use std::io::stdin;
let mut buff = String::new();
stdin().read_line(&mut buff)
.expect("Failed to read line.");
println!("input is {}", buff);
读取环境变量
use std::env;
let v = env::var("PATH").unwrap();
println!("PATH = {}", v);
读写文件
文件写入
use std::fs;
const FILE_PATH: &str = "test.txt";
fs::write(FILE_PATH, "FROM RUST PROGRAM").unwrap();
use std::fs::File;
const FILE_PATH: &str = "test.txt";
let mut f = File::create(FILE_PATH).unwrap();
f.write("FROM RUST PROGRAM".as_bytes());
use std::fs::OpenOptions;
use std::io::Write;
const FILE_PATH: &str = "test.txt";
let mut file = OpenOptions::new()
.append(true).open(FILE_PATH).unwrap();
file.write(b" APPEND WORD").unwrap();
文件读取
use std::fs;
const FILE_PATH: &str = "test.txt";
let text = fs::read_to_string(FILE_PATH).unwrap();
println!("{}", text);
use std::fs;
const FILE_PATH: &str = "test.txt";
let content_bytes = fs::read(FILE_PATH).unwrap();
String::from();
let content = String::from_utf8(content_bytes).unwrap();
println!("{}", content);
use std::io::Read;
use std::fs::File;
const FILE_PATH: &str = "test.txt";
let mut f = File::open(FILE_PATH).unwrap();
let mut buff = [0u8; 64];
let len = f.read(&mut buff).unwrap();
println!("len = {}", len);
let content = Vec::from(&buff[..len]);
let content = String::from_utf8(content).unwrap();
println!("content = {}", content);
函数式编程
Closure
Lambda表达式
|arg0: ParameterType, ...| -> FunctionType { ... }
|arg0: ParameterType, ...| ...
|arg0, ...| ..
|| ...
// lambda(完整)
let ladd1 = |x: i32, y: i32| -> i32 { x + y };
println!("ladd1(2, 3) = {}", ladd1(2, 3));
// lambda(省略返回类型)
let ladd2 = |x: i32, y: i32| x + y;
println!("ladd2(2, 3) = {}", ladd2(2, 3));
// lambda(省略变量类型、返回类型)
let ladd3 = |x, y| x + y;
println!("ladd3(2, 3) = {}", ladd3(2, 3));
// lambda(无参数)
let r = || 32;
println!("{}", r());
所有权捕获
use core::ops::{FnOnce, FnMut, Fn};
// 实际使用中往往由编译器推断确定。
FnOnce
移动捕获:闭包只能被调用一次。
let s = String::new();
let f = move || -> String { // move关键字可以省略
let mut c = s; // 所有权转移(入)
c.push_str("+");
c // 所有权转移(出)
};
// println!("s = {}", s); // Error: borrow of moved value: `s`
println!("f() = {}", f()); // It's ok
// println!("f() = {}", f()); // Error: borrow of moved value: `s`
// println!("s = {}", s); // Error: borrow of moved value: `s`
FnMut
可变借用捕获:
let mut s = String::new();
let mut f = || {
s.push_str("+");
};
f(); f(); f(); // It's ok
println!("s = {}", s); // It's ok
Fn
不可变借用捕获:
let w = "word";
let f = || -> String {
let mut s = String::new();
s.push_str(w);
s
};
println!("s = {}", f()); // It's ok
println!("s = {}", f()); // It's ok
Iterator
Rust中Iterator
被定义为
// use std::iter::Iterator;
trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// ...
}
消费迭代器
// use std::vec::Vec;
use core::slice::Iter; // impl FusedIterator : Iterator
use core::iter::Map; // impl FusedIterator : Iterator
let a: Vec<i32> = vec![1, 2, 3];
let a_it: Iter<i32> = a.iter();
let a_map: Map<Iter<i32>, fn(&i32) -> i32>
= a_it.map(|x: &i32| -> i32 { x * 2 });
for it in a_map.clone() {
print!("it = {}, ", it);
}
println!();
let a_coll: Vec<i32> = a_map.clone().collect();
println!("a_coll = {:?}", a_coll);
let a_sum: i32 = a_map.sum();
println!("a_sum = {}", a_sum);
// it = 2, it = 4, it = 6,
// a_coll = [2, 4, 6]
// a_sum = 12
自定义迭代器
struct CounterIter {
start_num: i32,
end_num: i32,
}
impl CounterIter {
fn new(start_num: i32, end_num: i32) -> CounterIter {
CounterIter { start_num, end_num }
}
}
impl Iterator for CounterIter {
type Item = i32;
fn next(&mut self) -> Option<Self::Item> {
if self.start_num >= self.end_num {
return None;
}
let r = Some(self.start_num);
self.start_num += 1;
r
}
}
for item in CounterIter::new(0, 6) {
print!("{}, ", item);
}
// 0, 1, 2, 3, 4, 5,
智能指针
指针类型
Box
Box
允许你将一个值放在堆上而不是栈上,留在栈上的则是指向堆数
据的指针。
let b = Box::new(5);
println!("b = {}", b);
Rc
引用计数。
enum List {
Cons(i32, Rc<List>),
Nil,
}
use List::{Cons, Nil};
use std::rc::Rc;
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
println!("count after creating a = {}", Rc::strong_count(&a));
let b = Cons(3, Rc::clone(&a));
println!("count after creating b = {}", Rc::strong_count(&a));
{
let c = Cons(4, Rc::clone(&a));
println!("count after creating c = {}", Rc::strong_count(&a));
}
println!("count after c goes out of scope = {}", Rc::strong_count(&a));
// count after creating a = 1
// count after creating b = 2
// count after creating c = 3
// count after c goes out of scope = 2
Cell&RefCell
Cell
和RefCell
在功能上没有区别,区别在于Cell<T>
适用于T
实现Copy
的情况。
使用RefCell<T>
能够在外部值被认为是不可变的情况下修改内部值。Box<T>
借用规则的不可变性作用于编译时。对于RefCell<T>
,这些不可变性作用于运行时。
use std::cell::Cell;
let c = Cell::new("asd");
println!("c = {}", c.get());
c.set("qwe"); // 此处违反借用规则,但可运行
println!("c = {}", c.get());
RefCell
实际上并没有解决可变引用和引用可以共存的问题。
use std::cell::RefCell;
let s = RefCell::new(String::from("hello, world"));
let bi = s.borrow();
let bm = s.borrow_mut();
println!("{}, {}", bi, bm);
// 没有编译器错误
// 存在运行时错误: already borrowed: BorrowMutError
Weak
弱引用,通常和Rc
协同使用解决引用循环问题。
递归类型
enum List {
Cons(i32, List), // Error: recursive type `List` has infinite size
Nil,
}
use List::{Cons, Nil};
let _ = Cons(1, Cons(2, Cons(3, Nil)));
使用智能指针进行递归存储:
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
let _ = Cons(
1, Box::new(Cons(
2, Box::new(Cons(
3, Box::new(Nil))))));
Deref
智能指针自动解引用。
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
let val = MyBox::new(5);
// println!("{}", *val); // Error: type `MyBox<{integer}>` cannot be dereferenced
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
println!("{}", *val);
// ↑↓ 等价
println!("{}", *(val.deref()));
Drop
离开作用域时操作代码。
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping `{}`!", self.data);
}
}
let _a = CustomSmartPointer { data: String::from("A") };
let _b = CustomSmartPointer { data: String::from("B") };
println!("Created!");
// Created!
// Dropping `B`!
// Dropping `A`!
Module
代码 | 说明 |
| 引入同级模块文件 |
| 创建文件内模块 |
| 引入同级模块方法 |
| 调用同级模块内方法 |
| 调用当前模块内方法 |
单文件
fn say_hello() {
println!("Hello mod_module!");
}
// 自定义模块
mod demo_module {
// private
fn say_hello() {
println!("Hello demo_module!");
}
// public
pub fn hello() {
// 调用私有方法
self::say_hello();
// 调用包含当前模块的模块内方法
super::say_hello();
}
}
pub fn main() {
demo_module::hello();
use demo_module::hello;
hello();
}
多文件
main.rs
mod mod_test0;
mod mod_test1;
fn main() {
mod_test0::hello();
mod_test1::hello();
mod_test1::mod_sub::hello();
// mod_test0 hello
// mod_test1 hello
// mod_sub hello
use mod_test0::hello as hello0;
use mod_test1::hello as hello1;
use mod_test1::{ mod_sub };
use mod_sub::*;
hello0();
hello1();
mod_sub::hello();
hello();
// mod_test0 hello
// mod_test1 hello
// mod_sub hello
// mod_sub hello
}
mod_test0.rs
pub fn hello() {
println!("mod_test0 hello");
}
mod_test1/mod.rs
pub mod mod_sub;
pub fn hello() {
println!("mod_test1 hello");
}
mod_test1/mod_sub.rs
pub fn hello() {
println!("mod_sub hello");
}
Macro
macro_rules! MacroName {
($arg0: ArguementType) => {...};
...
}
- 宏被调用时,会由上而下对每个规则进行匹配
- 宏调用所使用的括号可以是
()
、[]
、{}
任意一种
使用$( ... ) [sep] */+/?
可以进行重复匹配
ArguementType | Note | Example |
| 函数定义或常量声明 | |
|
| |
| 语句 |
|
| 模式 |
|
| 表达式 |
|
| 类型 |
|
| 标识符或关键字 |
|
| 模块路径 |
|
| Token树 | |
| 属性 |
|
| 生命周期Token |
|
| 可能为空的限定符 |
|
| 字面量 |
macro_rules! build_vec {
(
$( $i:expr ) , * // 重复匹配表达式
$( , )? // 可选的末尾逗号
) => {
{ // 表达式
let mut vec = Vec::new();
$( vec.push($i); )* // 重复添加
vec // 返回
}
}
}
let vs = build_vec!(1, 1 + 2, 2 + 3, );
println!("vs = {:?}", vs);
// vs = [1, 3, 5]
unsafe
需要unsafe的场景:
- 解裸指针
*const i32
、*mut i32
- 调用
unsafe fn
- 调用
extern
中内容 - 访问或修改
static mut
变量 - 实现
unsafe trait
unsafe fn dangerous() {}
unsafe {
dangerous();
}
extern "C" {
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
}
static mut COUNTER: u32 = 0;
unsafe {
COUNTER += 1;
println!("COUNTER: {}", COUNTER);
}
Thread
use std::thread::{self, JoinHandle};
use std::time::Duration;
// 子线程
let handle: JoinHandle<_> = thread::spawn(|| {
for i in 1..10 {
println!("spawn thread: {}", i);
thread::sleep(Duration::from_millis(1));
}
});
// 主线程
for i in 1..5 {
println!("main thread: {}", i);
thread::sleep(Duration::from_millis(1));
}
// 当<主线程>结束时,<子线程>也会结束
join
主线程等待子线程执行完毕。
use std::thread::{self, JoinHandle};
use std::time::Duration;
// 子线程
let handle: JoinHandle<_> = thread::spawn(|| {
for i in 1..10 {
println!("spawn thread: {}", i);
thread::sleep(Duration::from_millis(1));
}
});
// 主线程
for i in 1..5 {
println!("main thread: {}", i);
thread::sleep(Duration::from_millis(1));
}
// 当<主线程>结束时,等待<子线程>结束
handle.join().unwrap();
use std::thread::{self, JoinHandle};
use std::time::Duration;
// 子线程
let handle: JoinHandle<_> = thread::spawn(|| {
for i in 1..10 {
println!("spawn thread: {}", i);
thread::sleep(Duration::from_millis(1));
}
});
// 等待<子线程>结束,再开始运行<主线程>
handle.join().unwrap();
// 主线程
for i in 1..5 {
println!("main thread: {}", i);
thread::sleep(Duration::from_millis(1));
}
channel
通道为单所有权,数据传入通道后将无法再使用。
use std::thread;
use std::sync::mpsc;
let (sender, receiver) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
sender.send(val).unwrap();
});
// 阻塞并接收值
let received = receiver.recv().unwrap();
println!("{}", received);
use std::thread;
use std::sync::mpsc;
use std::time::Duration;
let (sender, receiver) = mpsc::channel();
thread::spawn(move || {
let val_list = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in val_list {
sender.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
// 阻塞并接收值
for received in receiver {
println!("- {}", received);
}
Mutex & Arc
在智能指针特性方面:
-
Mutex<T>
类似于RefCell<T>
-
Arc<T>
类似于Rc<T>
Mutex<T>
和Arc<T>
为多所有权。
use std::sync::{Mutex, MutexGuard};
let mutex = Mutex::new(5);
{
// 获取锁,返回可写智能指针(MutexGuard)
let mut num: MutexGuard<_> = mutex.lock().unwrap();
*num = 6;
// 退出作用域时自动释放锁
}
println!("m = {:?}", mutex);
// m = Mutex { data: 6, poisoned: false, .. }
Sync & Send
// Rust 中的两个空实现 trait
use std::marker::{Sync, Send};
Send
表明类型的所有权可以在线程间传递。除了Rc<T>
外,几乎所有的Rust类型都是Send
的。
Sync
表明一个实现了Sync
的类型可以安全的在多个线程中拥有其值的引用。Rc<T>
、RefCell<T>
、Cell<T>
不是Sync
的。
Socket
Tcp
tcp_server/main.rs
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
fn handle_client(mut stream: TcpStream) {
let mut buffer = [0u8; 128];
loop {
// 读取消息
let length = stream.read(&mut buffer).unwrap();
let content = std::str::from_utf8(&buffer[..length]).unwrap();
println!("{}, content = {}", length, content);
// 回复消息
let message = format!("received: {}", content);
stream.write(message.as_bytes()).unwrap();
stream.flush().unwrap();
}
}
fn main() {
let listener = TcpListener::bind("127.0.0.1:8888").unwrap();
// 对每一个连接开启一个线程进行处理
for stream in listener.incoming() {
std::thread::spawn(move || {
handle_client(stream.unwrap());
});
}
}
tcp_client/main.rs
use std::io::{self, Read, Write};
use std::net::TcpStream;
fn main() {
let mut stream = TcpStream::connect("127.0.0.1:8888").unwrap();
let mut length: usize;
let mut buffer = [0u8; 128];
loop {
// 从命令窗口读取消息
length = io::stdin().read(&mut buffer).unwrap();
stream.write(&buffer[..length]).unwrap();
stream.flush().unwrap();
// 查看消息
let length = stream.read(&mut buffer).unwrap();
let content = std::str::from_utf8(&buffer[..length]).unwrap();
println!("{}, content = {}", length, content);
}
}
UdpBroadcast
udp_broadcast_server/main.rs
use std::net::{SocketAddr, UdpSocket, Ipv4Addr};
fn main() {
let bind_socket_address = SocketAddr::from("0.0.0.0:8888");
let multi_address = Ipv4Addr::new(234, 2, 2, 2);
let socket = UdpSocket::bind(bind_socket_address).unwrap();
let mut buffer = [0u8; 65535];
socket.join_multicast_v4(&multi_address, &Ipv4Addr::UNSPECIFIED).unwrap();
loop {
let (size, source_address) = socket.recv_from(&mut buffer).unwrap();
let message = std::str::from_utf8(&buffer).unwrap();
println!("Received {} bytes from {:?}", size, source_address);
println!("message = {}", &message[..size]);
}
}
udp_broadcast_client/main.rs
use std::net::{Ipv4Addr, SocketAddr, UdpSocket};
fn main() {
let bind_socket_address = SocketAddr::from((Ipv4Addr::UNSPECIFIED, 9999));
let multi_socket_address = SocketAddr::from(([234, 2, 2, 2], 8888));
let socket = UdpSocket::bind(bind_socket_address).unwrap();
let message = "Hello Udp Broadcast!";
socket.send_to(message.as_bytes(), multi_socket_address).unwrap();
}