关于Rust

2023-10-26

Rust

文章目录

开发环境搭建

在线模式

  • S t e p 2 Step2 Step2:下载Rustup安装程序;
  • S t e p 3 Step3 Step3:打开命令窗口输入以下命令:
@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
  • S t e p 4 Step4 Step4:提示缺少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
  • S t e p 5 Step5 Step5:自定义安装信息:
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>2
  • S t e p 6 Step6 Step6:配置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
  • S t e p 7 Step7 Step7:继续安装等待安装完成:
1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1

离线模式

  • S t e p 2 Step2 Step2:下载Standalone installers
    • x86_64-windows: x86_64-pc-windows-gnu
    • x86_64-linux: x86_64-unknown-linux-gnu
    • aarch: aarch64-unknown-linux-gnu
  • S t e p 2 Step2 Step2:下载Source Code
  • S t e p 3 Step3 Step3:下载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!("\\");
说明
{} 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
#[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展开

unwrapexpect可简化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

CellRefCell在功能上没有区别,区别在于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

代码 说明
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 标识符或关键字 iself
path 模块路径 std::result::Result
tt Token树
meta 属性 #[...]
lifetime 生命周期Token static
vis 可能为空的限定符 pub
literal 字面量
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();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关于Rust 的相关文章

随机推荐

  • 5.QT5中的connect的实现

    在QT4中 解析信号槽是通过将信号槽的名字转化为字符串 然后通过connect解析该字符串 得到信号函数的相对序号和 然后创建信号connectionlist 但是 所有的检查都在运行时 通过解析字符串进行 这意味着 如果信号槽的名称拼写错
  • springcloud之服务配置中心

    springcloud之服务配置中心 SpringCloud Config简介 Config Server基本使用 Config Client基本使用 Config整合Eureka Config配置搜索路径 SpringCloud Conf
  • 2021.11.7总结

    数据结构 将第三章栈与队列知识点看完了 栈是先进后出表 队列是先进先出表 然后发现了书上有很多题目 慕课上面也有很多题目 只是我自己没写而已 下周从第一章开始写题 然后洛谷很久没写题目了 下周 将数据结构书上和课程的题目写完 到第三章 洛谷
  • 开启OLED透明屏代理之路:高质量显示解决方案的商机

    随着科技的不断进步 OLED透明屏作为一种创新的显示技术 正逐渐在各个领域得到广泛应用 作为一名OLED透明屏代理商 你将有机会参与其中 共享这一蓬勃发展的市场 一 介绍OLED透明屏的概念和特点 1 1 什么是OLED透明屏 OLED透明
  • pandas_数据处理分析基本

    一 Pandas基础用法 20210405 fancy lee 1 pandas介绍 Python Data Analysis Library 或 pandas 是基于NumPy 的一种工具 该工具是为了解决数据分析任务而创建的 panda
  • ESP-12F开发环境

    ESP 12F可以使用arduino IDE快速开发 1 首先安装arduino IDE 搜索直接下载即可 2 在文件 gt 首选项 gt 附加开发板管理器网址中添加ESP8266开发板 网址 http arduino esp8266 co
  • PHP curl 传输文件流

    PHP版本5 5以下时可直接使用 拼接要传输的文件的绝对路径即可 params file str replace ABSOLUTE PATH str PHP版本5 5以上时 需要使用curl file create函数 创建一个 CURLF
  • Python中Pickle模块的dump()方法和load()方法

    Python中的Pickle模块实现了基本的数据序列与反序列化 一 dump 方法 pickle dump obj file protocol 注释 序列化对象 将对象obj保存到文件file中去 参数protocol是序列化模式 默认是0
  • docker 使用pytorch在gpu上训练模型

    docker 使用pytorch在gpu上训练模型 安装docker 下载docker image 建立启动容器进入docker虚拟空间 不一定能运行起来 安装docker sudo apt get y install docker io
  • 百度旋转验证码(8-24,js逆向)

    网址 aHR0cHM6Ly96aXl1YW4uYmFpZHUuY29tL2xpbmtzdWJtaXQvdXJs 一 抓包分析 刷新网页 先看第一个包 提交参数是ak和时间戳 ak是定值 返回的参数中 as和tk后面都会用到 然后点击提交链接
  • Android AnimationDrawable动画与APP启动引导页面

    Android AnimationDrawable动画与APP启动 加载引导页面 画面 AnimationDrawable是Android的Frame动画 可以简单的认为此AnimationDrawable能够将一系列资源图片加载成 电影
  • 大数据分析引擎之presto简介

    大数据分析引擎之presto简介 简介 presto是一个大数据分析引擎 不属于hadoop体系 他是基于内存的 他的集群模式是主从式的 他可以与任何的大数据存储引擎做集成 集成的时候使用它的Connectors集成 从这里我们可以他可以和
  • SpringBoot集成mybatis-plus生成实体类

    1 pom xml添加依赖 2 配置mybatis plus 在application yml中添加 配置数据库连接 3 在com dtest02 demo system config下添加MyBatisPlusConfig java 4
  • 踩坑:nacos利用startup.cmd -m standalone启动错误

    1 报错信息 PS D SpringCloud nacos nacos bin gt startup cmd m standalone startup cmd 无法将 startup cmd 项识别为 cmdlet 函数 脚本文件或可运行程
  • 线性代数 --- 最小二乘在直线拟合上的应用与Gram-Schmidt正交化(上)

    最小二乘在直线拟合上的应用 在前一篇最小二乘的文章中 线性代数 投影与最小二乘 下 多元方程组的最小二乘解与向量在多维子空间上的投影 松下J27的博客 CSDN博客多变量方程组的最小二乘 向量到多维子空间上的投影 https blog cs
  • 如何找数组中唯一重复的数?

    如何找数组中唯一重复的数 题目 方法一 不使用辅助空间的方法 思路 1 异或 同0异1 2 一组数连续异或 相当于消除重复的数 所以可以把1到1000这1000个数异或以后 和数组中的1001个元素异或 这样结果就是重复的元素 例 数组为
  • 热门面试题

    Transactional失效场景 没有将使用该注解的类交给Spring管理 也就是该对象不是bean对象 Transactional 应用在非 public 修饰的方法上 同一个类中方法之间的调用 导致 Transactional 失效
  • L - Sticky Situation

    L Sticky Situationhttps vjudge csgrandeur cn problem Kattis stickysituation 题意 给定一个 n 和 n 个数 看存不存在三个数可以构成三角形 include
  • hive中的EXPLODE和LATERAL VIEW

    行转列操作 0 函数说明 EXPLODE col 将 hive 一列中复杂的 array 或者 map 结构拆分成多行 LATERAL VIEW 用法 LATERAL VIEW udtf expression tableAlias AS c
  • 关于Rust

    Rust 文章目录 Rust 开发环境搭建 在线模式 离线模式 引入自定义第三方库 通用编程概念 Hello 注释 印屏 Display 变量 变量可变性 不可变变量与常量 变量冻结 延迟绑定 变量隐藏 数据类型 基本数据类型 类型别名 简