windows2019 自建rustdesk服务器
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安装程序;
- :打开命令窗口输入以下命令:
- :提示缺少Microsoft C++ build tools,回车继续;
- :自定义安装信息:
- :配置default host triple,其它选择直接回车使用默认:
最终配置如下:
default host triple: x86_64-pc-windows-gnu default toolchain: stable profile: default modify PATH variable: yes- :继续安装等待安装完成:
离线模式
- :下载Standalone installers;
- 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.tomlREM 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!("\\");说明
{}
Display trait
{:?}
Debug trait
{:e}
LowerExp trait
{:E}
UpperExp trait
{:o}
Octal trait
{:p}
Pointer trait
{:b}
Binary trait
{:x}
LowerHex trait
{:X}
UpperHex trait
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);不可变变量与常量
- 声明常量时,必须注明值的类型。
- 常量可以在任何作用域声明,包括全局作用域。
- 常量不能作为函数调用的结果。
变量冻结
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: @0xa7fb4clet 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 = 0From和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 = 0xa8fae0Array
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] = 0Array长度固定,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.4Struct
#[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));条件语句
- 条件必须是布尔值。
- 大括号不可省。
循环语句
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所有权转移
- 每个值都有且仅有一个所有者。
- 当所有者离开作用域时,变量会被回收。
引用与借用
获取值的引用,但不获取其所有权称为借用(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) }裸指针
- 允许忽略借用规则,可以同时拥有不可变和可变的指针,或多个指向相同位置的可变指针
- 不保证指向有效的内存
- 允许为空
- 不能实现任何自动清理功能
切片(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 4Rust 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 unloadedOption
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 = trueif 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引用包含两个指针:
- 指向数据
- 指向方法调用名称与函数指针的映射
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, ...| ..
- || ...
所有权捕获
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 okFn不可变借用捕获:
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 okIterator
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允许你将一个值放在堆上而不是栈上,留在栈上的则是指向堆数
据的指针。
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 = 2Cell&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: BorrowMutErrorWeak
弱引用,通常和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
代码
说明
mod ...;
引入同级模块文件
mod ... {}
创建文件内模块
use crate::...;
引入同级模块方法
crate::...();
调用同级模块内方法
self::...();
调用当前模块内方法
单文件
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
item
函数定义或常量声明
block
{ ... }
stmt
语句
let x = 32
pat
模式
Some(a)
expr
表达式
Vec::new()
ty
类型
i32
ident
标识符或关键字
i、self
path
模块路径
std::result::Result
tt
Token树
meta
属性
#[...]
lifetime
生命周期Token
static
vis
可能为空的限定符
pub
literal
字面量
unsafe
需要unsafe的场景:
- 解裸指针*const i32、*mut i32
- 调用unsafe fn
- 调用extern中内容
- 访问或修改static mut变量
- 实现unsafe trait
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(); }