WJ-Yuan / Notes

My Tech Notes
https://wj-yuan.github.io/Notes/
0 stars 0 forks source link

[Notes] Rust Notes #5

Open WJ-Yuan opened 1 year ago

WJ-Yuan commented 1 year ago

目录

WJ-Yuan commented 1 year ago

参考资料:

  1. Rust by Example
  2. Easy Rust
  3. The Rust Programming Language
  4. Rust语言圣经(Rust Course)
WJ-Yuan commented 1 year ago

变量及基础数据类型

/**
 * 变量
 * 类型有 整型(8, 16, 32, 64, 128, size)、浮点型(8, 16, 32, 64, 128, size)、布尔型(true/false)、字符型(char)
 */
fn main() {
    // 默认整型是 i32,浮点是 f64
    let a: i32 = 5;
    let b: f64 = 1.2;
    let bb: bool = true;
    let c: char = 'd';
    let smile: char = '\u{1F601}';
    let str_item: &str = "一个字符串";
    println!("{}, {}, {}, {c}, {smile}, {str_item}", a, b, bb);
}
WJ-Yuan commented 1 year ago

控制流

/**
 * 控制流 - 条件
 * if...else
 */
/**
 * 控制流 - 循环
 * loop 或 iteration
 * 
 * 关键字
 * - loop 无尽的循环
 * - while 有条件的循环
 * - for 
 * 
 * 可以通过 break 退出循环
 * 通过 continue 退出当前循环
 */
const MAX: i32 = 10;

fn main() {
    println!("Hello, World!");
    let mut num: i32 = 0;
    while num * num < 10 {
        if num == 2 {
            num += 1;
            continue;
        }

        println!("while: {0} * {0} = {1}", num, num * num);
        num += 1;
    }

    let mut num: i32 = 0;
    loop {
        println!("while: {0} * {0} = {1}", num, num * num);
        num += 1;
        if num * num > MAX {
            break;
        }
    }
}
/**
 * match
 * 
 * 在流程控制这块,和 if...else 类似,但是必须写出所有条件下的执行代码
 * 
 * match vs if...else
 * 
 * - match 会在编译时检查错误
 * - if...else 则不会,只会在运行时报错
 */
use rand::Rng;

fn main() {
    let mut rng = rand::thread_rng();
    let num = rng.gen_range(0..10);

    if num > 5 {
        println!("{num} > 5");
    } else if num == 5 {
        println!("{num} == 5");
    } else {
        println!("{num} < 5");
    }

    match num {
        2 => println!("ok"),
        5..=9 => println!("unknown"),
        _ => println!("{num}"),
    }
}
WJ-Yuan commented 1 year ago

函数

/**
 * 函数
 * 最后一行不加 ";",自动作为值返回
 */
// 普通函数
fn add_fun(a: i32, b:i32) -> i32 {
    println!("a: {a}");
    println!("b: {b}");
    a + b
}

fn main() {
    let res = add_fun(8, 9);
    println!("{res}");
}

/**
 * 闭包
 * 又叫函数中的函数,匿名函数
 * 也就是 lambda 表达式
 */
fn main() {
    let sum = |a: i32, b: i32| -> i32{a + b};
    let res = sum(3, 4);
    println!("{res}");
}
WJ-Yuan commented 1 year ago

复合数据类型

Enum

/**
 * 枚举 Enum
 * 
 * 提高代码可读性;
 * 提供标识给编译器(提高性能)
 * 
 * 系统内置
 * Result
 * Option
*/
#[derive(Debug)] // 便于用 print 打印
enum Position {
    Left,
    Right
} 

fn return_right(enum_item: Position) -> Position {
    println!("{:?}", enum_item);
    Position::Right
}

fn main () {
    let pos = Position::Left;
    match pos {
        Position::Left => println!("left"),
        Position::Right => println!("right"),
    }
    println!("{:?}", pos);

    let right: Position = return_right(pos);
    println!("{:?}", right);

}

struct

/**
 * 结构体 struct
 * rust 中没有 class
 * 
 * 属性
 * struct 包含多段数据的类型
 * 每一段数据被称为 field 属性
 * 访问属性用 . 操作符 
 * 
 *
 * struct 方法
 * 
 * 类型:
 * - 关联函数
 * - 实例方法
 * 
 * 
 * 构造函数及 self
 */
#[derive(Debug)] // 如果要 println 打印复合类型需要加这个
struct Rectangle {
    width: i32,
    height: i32
}

fn new(width: i32, height: i32) -> Rectangle {
    Rectangle {
        width,
        height
    }
}

impl  Rectangle {
    // 构造函数
    fn new(width: i32, height: i32) -> Self {
        Rectangle {
            width,
            height
        }
    }

    fn area(width: i32, height: i32) -> i32 {
        width * height
    }

    fn self_area(&self) -> i32 {
        self.width * self.height
    }
}

fn main() {
    let rect = Rectangle::new(3, 4);
    println!("{}, {}", rect.width, rect.height);
    println!("{:?}", rect);
    println!("{:#?}", rect); // 打印格式化

    let area = Rectangle::area(rect.width, rect.height);
    println!("{}", area);

    let area_self = Rectangle::self_area(&rect);
    println!("{}", area_self);

    let rect_2 = new(3, 4);
    println!("{:#?}", rect_2)
}
/**
 * self
 * 
 * &self
 * &mut self
 * self
 * mut self  - 用得很少
 */
#[derive(Debug)]
struct Person {
    name: String,
    age: i32,
}

impl Person {
    pub fn new(name: String, age: i32) -> Self{ Person { name, age } }

    // 类似 this 指针,但是是不可变的,可变的需要加 mut
    fn greet(&self) -> String {
        format!("Hi {}", self.name)
    }

    fn up_age(&mut self, n:i32) {
        self.age += n;
    }

    // self 一般用来销毁
    fn drop_self(self) {
        println!("drop self");
    }
}

fn main() {
    let mut person: Person = Person::new("david".to_string(), 30);
    println!("{:#?}", person);

    println!("{}", person.greet());
    person.up_age(3);
    println!("{}", person.age);
    person.drop_self();
}

元组

/**
 * 元组 tuple
 * 相似类型有数组、切片,但在 rust 中不常用,常用 Vector
 * 
 * - 匿名存储数据
 * - 不可变
 * 
 * 元组的用处
 * - 函数返回
 * - 提取变量
 */

#[derive(Debug)]
enum In {
    Oh
}

fn one_two_three() -> (i32, i32, i32) {
    (1, 2, 3)
}

fn main() {
    let numbers = one_two_three();
    println!("{:?}", numbers);
    let (x, y, z) = one_two_three();
    println!("x {} y {} z {}", x, y, z);
    let (man, action) = ("david", In::Oh);
    println!("man: {}, in: {:?}", man,action);
}
WJ-Yuan commented 1 year ago

所有权机制

/**
 * 
 * OwnerShip
 * 
 * - move & borrowed
 * - clone & copy
 * - reference
 * - lifetime
 * 
 * 
 * ownership model
 * 
 *  ownership 规则
 * - 每个值都有一个变量称为所有者
 * - 每个值同时只能有一个所有者
 * - 当所有者超出作用域时,值被销毁
 * 
 * Stack 和 Heap
 * - Stack 存储已知的大小的数据;快;基础数据类型等
 * - Heap 存储未知大小的数据;慢;Struct 等
 **/

/**
 * move 可理解为
 * 
 * 浅拷贝 + 失效
 * 
 * let a = "ff".to_string();
 * let b = a; // a 失效
 * 
 * 
 * copy/clone 可理解为
 * 
 * 深度拷贝 开辟新的空间
*/
#[derive(Debug)]
struct A {
    a: i32,
}

fn main() {
    let a: &str = "str";
    let b: &str = a;
    println!("{}, {}", a, b);

    // let p: String = "str".to_string();
    // let q: String = p;
    // 此时 p 会报错: borrow of moved value: `p` value borrowed here after move
    // println!("{}, {}", p, q);

    // let m: A = A{a: 7};
    // let n = m;
    // // 此时 m 会报错:borrow of moved value: `m` value borrowed here after move
    // println!("{:?}, {:?}", m, n);
}
/**
 * 引用和可变引用
 * 
 * & 和 &mut
 * 
 * 
 * 在同一作用域下,对某一块数据:
 * - 可以有多个不可变引用
 * - 只能有一个可变的引用
 * - 不能同时拥有一个可变引用和一个不可变引用
 */
struct A {
    a: i32
}

fn r(a: A) {
    println!("{}", a.a);
}

fn rr(a: &A) {
    println!("{}", a.a);
}

fn rrr(a: &mut A) {
    a.a = 74520;
}
fn main() {
    let a = A {a: 4};
    println!("{}", a.a);

    rr(&a);
    println!("{}", a.a);

    r(a);
    // 报错 borrow of moved value: `a` value borrowed here after move
    // println!("{}", a.a);

    let mut b = A {a: 3};
    println!("{}", b.a);
    rrr(&mut b);
    println!("{}", b.a);

    let mut s = "ke".to_string();
    let ss = &mut s;
    let s = &mut s; // cannot borrow `s` as mutable more than once at a time second mutable borrow occurs here
    ss.push('h');

}
/**
 * copy & clone 
 * 
 * 二者都是 trait 特质
 */
#[derive(Debug, Clone)]
struct Person {
    name: String,
    age: i32
}

fn main() {
    let person = Person {
        name: "david".to_string(), 
        age: 9
    };

    let ok: Person = person.clone();
    println!("{:?}, {:?}", person, ok);
}

#[derive(Debug, Clone, Copy)]
struct Person<'a> {
    name: &'a str,
    age: i32
}

fn main() {
    let person = Person {
        name: "david", 
        age: 9
    };

    let ok: Person = person;
    println!("{:?}, {:?}", person, ok);
}
/**
 * 生命周期 lifetime
 * 
 * 避免 dangling reference
 * rust 中所有的引用都有自己的生命周期,表示引用有效的作用域
 * 一般为隐式的,但不可推断时会保错,需要手动标注生命周期
 * 
 * 一般不要用 'static
 * 
 * 省略规则
 * - 每个引用类型的参数都有自己的生命周期
 * - 只有一个输入生命周期参数,那么输入生命周期就为该生命周期
 * - 有 &self 或 &mut self,那么输出生命周期就为该 self 生命周期
 */

// a, b 和返回值是同一个作用域,以最短的生命周期为有效
fn longest<'a>(a: &'a str, b: &'a str) -> &'a str {
    if a.len() > b.len() {
        a
    } else {
        b
    }
}
fn main() {

}
WJ-Yuan commented 1 year ago

String

/**
 * 常用数据类型 String
 * 
 * &str:String slices 不可变的,放在栈上
 * let cat = "cat";
 * 
 * 
 * String object  放在堆上
 * let dog = String::new();
 * let dog = String::from("sd");
 * let dog = "s".to_string();
 * 通过 format! 生成
 */

 /**
  * String 方法
  len()
  push 字符
  push_str
  replace
  */
fn main() {
    let cat: &str = "cat";
    println!("cat: {cat}");

    let dog = String::new();
    println!("dog: {dog}");

    let dog = String::from("sd");
    println!("dog: {dog}");

    let mut dog = "s".to_string();
    dog.push('f');
    dog.push_str("david");

    println!("dog: {dog}");
    println!("{}", dog.replace("id", "-dd-"));

    let dog = format!("{}", 1);
    println!("dog: {dog}");
    println!("dog len: {}", dog.len());
}
WJ-Yuan commented 1 year ago

Vector

/**
 * 常用数据类型 Vector 可变数组
 * 
 * 构造
 * let arr = Vec::new();
 * let arr = vec![1, 2];
 * let arr = vec![1;20];
 * 
 * 方法
 * push & remove
 */
fn main() {
    let mut arr1: Vec<i32> = Vec::new();
    arr1.push(1);
    println!("{:?}", arr1);

    let mut arr2: Vec<i32> = vec![1,2];
    arr2.push(3);
    println!("{:?}", arr2);

    let mut arr3: Vec<i32> = vec![1;20];
    arr3.remove(0);
    println!("{:?}", arr3);
    // [1]
    // [1, 2, 3]
    // [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

    // println!("{}", arr3[21]); // 越界运行会报错
    match arr3.get(21) {
        Some(item) => println!("{}", item),
        None => {}
    }

    for item in arr3.iter() {
        println!("{}", item);
    }

}
WJ-Yuan commented 1 year ago

HashMap

/**
 * HashMap
 * 
 * 散列函数把消息或数据压缩为摘要,使得数据量变小,将数据的格式固定下来。
 * 该函数将数据打乱混合,重新创建一个叫做散列值(hash values, hash codes, hash sums 或 hashes)的指纹
 * 
 * HashMap 由 链表 + 数组 组成,他的底层结构是一个数组,而数组的元素是一个单向链表
 * 
 * rust 中 HashMap 的键可以是布尔型、整型、字符串或任意实现了 Eq 和 Hash trait 的其他类型
 * HashMap 也是可增长的,但 HashMap 在占据了多余空间时还可以缩小自己
 */
use std::collections::HashMap;

fn main () {
    let mut string_map: HashMap<&str, i32> = HashMap::new();
    string_map.insert("david", 51);
    string_map.insert("david2", 56);
    println!("{:#?}", string_map);

    match string_map.get(&"david2") {
        Some(&age) => println!("david2 is {} years old", age),
        None => {},
    }

    string_map.remove(&"david");
    for pair in string_map.into_iter() {
        println!("{}, {}", pair.0, pair.1)
    }
}
WJ-Yuan commented 1 year ago

traits

/**
 * traits
 * 
 * 与接口和抽象类类似
 * 给结构体添加定义的行为
 * 
 * impl trait_demo for struct_demo
 * 
 * 返回特质时需要加 Box
 * fn get_trait() -> Box<dyn trait_name>
 */
struct A {
    name: String
}

impl Person for A {
    fn new(awesome: String) -> Self {
        A {
            name: awesome
        }
    }
    fn language(&self) -> &str {
        "A"
    }
}

struct B {
    name: String
}

impl Person for B {
    fn new(awesome: String) -> Self {
        B {
            name: awesome
        }
    }
    fn language(&self) -> &str {
        "B"
    }
    fn say_hello(&self) {
        println!("a hello world, {}", self.name);
    }
}

trait Person {
    fn new(awesome: String) -> Self;
    fn language(&self) -> &str;
    fn say_hello(&self) {
        println!("hello world");
    }
}
fn main() {
    let a: A = A::new("david_a".to_string());
    let b: B = B::new("david_b".to_string());
    a.say_hello();
    b.say_hello();
}
WJ-Yuan commented 1 year ago

Generics

/**
 * generics
 * 
 * 泛型时程序设计语言的一种风格或范式
 * 在强类型程序设计语言编写代码时使用一些以后才指定的类型,在实例化时作为参数声明这些类型
 */
trait Bark {
    fn bark(&self) -> String;
}

struct Dog {
    species: String
}

struct Cat {
    color: String
}

impl Bark for Dog {
    fn bark(&self) -> String {
        format!("{} barking", self.species)
    }
}

fn bark<T: Bark>(b: T) {
    println!("{}", b.bark());
}
fn main() {

    let dog = Dog{species: "yellow".to_string()};
    bark(dog);

    let cat = Cat { color: "white".to_string() };
    bark(cat); // the trait bound `Cat: Bark` is not satisfied
}