学习知识的目的,是让我们捕捉各种表象背后的本质,让我们走出下愚的死循环,步入到上智的境界。

Rust 基础练习笔记

下面代码是用差不多一天时间整理出来的一些基础笔记,发现学一门新语言用这种方式更高效些,然后再做一些的项目,如命令行程序等,还有看开源的程序代码等,差不多可以入门了。

fn main() {
    for_const();
    for_var();
    for_condition();
    for_loop();
    for_tuple();
    for_array();
    for_ownership();
    for_borrow();
    for_slice();
    for_struct();
    for_enum();
    for_mod();
    for_collections();
    for_error();
    for_closure();
    for_pointer();
    for_thread();
    for_stdin();
    for_file();
}
// 常量
fn for_const() {
    mark("常量");
    // 基本数据类型(整型,浮点型,布尔类型,字符类型)
    // 1.只能赋值,名称要大写
    // 2.数据类型不可以忽略
    // 3.不能出现同名
    const SERVER: &'static str = "https://zee.kim";
    const PORT: u16 = 8080;
    println!("常量: {}:{}", SERVER, PORT);
}
// 设置类型和变量
fn for_var() {
    mark("设置类型和变量");
    /*
    大小	有符号	无符号
    8 bit	i8	    u8
    16 bit	i16	    u16
    32 bit	i32	    u32
    64 bit	i64	    u64
    128 bit	i128	u128
    Arch	isize	usize(x86 机器上为 32 位,在 x64 机器上为 64 位)
    */
    let _int: usize = 1024;
    println!("整数: {}", _int);
    println!("最大整数: {}", std::u128::MAX);
    println!("最小整数: {}", std::i128::MIN);

    let _float: f64 = 89_898.141_526; //数字分隔符“_”,更容易看清
    println!("浮点: {}", _float);

    let _bool: bool = true;
    println!("布尔值: {}", _bool);

    let _string: &str = "Huawei♥♥";
    println!("字符串: {}", _string);

    let empty_string = String::new();
    println!("长度是 {}", empty_string.len());
    let content_string = String::from("简单教程");
    println!("长度是 {}", content_string.len());

    let name1 = " 幸福彼岸".to_string(); //原字符串对象
    println!("去掉左右空格/回车/换行/制表符:{}", name1.trim());
    let name2 = name1.replace("彼岸", "使者"); // 查找并替换
    println!("{}", name2);
    let name3 = name2.contains("使者"); // 是否包含
    let name4 = "#".repeat(4); //重复
    println!("{}=>{}", name3, name4);
    let name5 = name2.as_str(); //将字符串对象转换为字符串字面量
    println!("{}", name5);
    let name6 = name2.trim().chars(); //将字符串打散为字符数组
    println!("{:?}", name6);

    let number = 2021;
    let number_as_string = number.to_string();

    // 转换数字为字符串类型
    println!("{}", number_as_string);
    println!("{}", number_as_string == "2021");

    // 格式化宏 format!
    let n1 = 1024;
    let n2 = "KB".to_string();
    let n3 = format!("{}{}", n1, n2);
    println!("{}", n3);

    // LET 变量
    // 1.变量名中可以包含 字母、数字 和 下划线。
    // 2.变量名必须以 字母 或 下划线 开头。
    // 3.变量名是 区分大小 写的。
    // 4.let 在第一次赋值之后不可重新赋值,如要变则要加mut
    let mut status = "yes";
    println!("status: {}", status);
    status = "no";
    println!("status: {}", status);
}
// 条件判断
// @不支持自增自减运算符 ++ 和 --
fn for_condition() {
    mark("条件判断");
    let score = 80;
    if score == 100 {
        println!("满分!");
    } else if score >= 80 {
        println!("合格");
    } else {
        println!("不合格!");
    }
    let sex = "1";
    let sex_string = match sex {
        "0" => "女",
        "1" => "男",
        _ => "",
    };
    println!("{}", sex_string);
}
// 循环语句
fn for_loop() {
    mark("循环语句");
    for x in 1..3 {
        println!("x is {}", x);
    }
    let mut xx = 0;
    loop {
        xx += 1;
        if xx == 1 {
            continue;
        }
        if xx == 5 {
            break;
        }
        println!("loop {}", xx);
    }
    let mut xxx = 0;
    while xxx < 3 {
        xxx += 1;
        println!("while {}", xxx);
    }
}
// 元组
fn for_tuple() {
    mark("元组");
    let tuple: (i32, f64, u8) = (-325, 4.9, 22);
    println!("{:?}", tuple);
    println!("integer is :{:?}", tuple.0);
    println!("float is :{:?}", tuple.1);
    println!("unsigned integer is :{:?}", tuple.2);
}
// 数组
// @数组中所有的元素的值初始化为 -1
// @数组可以理解为相同数据类型的值的集合
// @数组的定义其实就是为分配一段 连续的相同数据类型 的内存块。
// @数组是静态的。这意味着一旦定义和初始化,则永远不可更改它的长度。
// @数组下标从 0 开始。
// @可以更新或修改数组元素的值,但不能删除数组元素。如果要删除功能,你可以将它的值赋值为 0 或其它表示删除的值。
fn for_array() {
    mark("数组");
    // 不可变
    let arr: [i32; 4] = [10, 20, 30, 40];
    println!("array is {:?}", arr);
    println!("array size is :{}", arr.len());

    for val in arr.iter() {
        println!("数组 :{}", val);
    }

    for key in 0..4 {
        println!("数组 key:{},value:{}", key, arr[key]);
    }

    // 可变
    let mut arr: [i32; 4] = [10, 20, 30, 40];
    arr[1] = 0;
    println!("可变数组 {:?}", arr);
}

// 所有权
// @所有权只会发生在堆上分配的数据
// @基本类型的存储都在栈上,因此没有所有权的概念。
fn for_ownership() {
    mark("所有权");
    let v = vec![1, 2, 3];
    let v2 = v; //这里v嫁给了v2,就销毁了,后面不能再用了
    println!("所有权 {:?}", v2);
}
// 借用
fn for_borrow() {
    mark("借用");
    fn echo(x: &Vec<i32>) {
        // 1. 第一步,定义参数接受一个引用
        println!("Inside print_vector function {:?}", x);
    }

    let v = vec![10, 20, 30];
    echo(&v); // 传递变量的引用给函数
    println!("{}", v[0]);
    // 可变的借用
    // 1.变量本身是可变更的,也就是定义时必须添加 mut 关键字。
    // 2.函数的参数也必须定义为可变更的,也就是必须添加 &mut 关键字。
    // 3.传递 借用 Borrowing 或者说引用也必须声明时 可变更传递,也就是传递参数时必须添加 &mut 关键字。
    fn mut_echo(x: &mut i32) {
        // 1. 第一步,定义参数接受一个引用
        *x = 2;
    }

    let mut v2 = 1;
    mut_echo(&mut v2);
    println!("{}", v2);
}
// 切片(一般使用=>数组 array、向量 vector、字符串 string)
// 1.一个 切片( slice ) 就是指向一段 内存 的指针
// 2.因此 切片 可用于访问内存块中 连续区间内的数据。
// 3.访问切片内容的时候,下标索引是从 0 开始的。
// 4.切片 的大小是运行时才可知的,并不是数组那种编译时就必须告知的。
fn for_slice() {
    mark("切片");
    let n1 = "ABCDEDF".to_string();
    println!("length: {}", n1.len());
    let s1 = &n1[0..5];
    println!("{}", s1);
}

// 结构体
// 1.结构体名 Name_of_structure 和元素/字段名 fieldN 遵循普通变量的命名语法。
// 2.结构体中中的每一个元素/字段都必须明确指定数据类型。可以是基本类型,也可以是另一个结构体。
fn for_struct() {
    mark("结构体");
    struct Employee {
        name: String,
        company: String,
        age: u32,
    }
    let e = Employee {
        company: String::from("哇哈哈"),
        name: String::from("小李"),
        age: 50,
    };
    println!(
        "Name is :{} company is {} age is {}",
        e.name, e.company, e.age
    );
    let mut e2 = Employee {
        company: String::from("哇哈哈"),
        name: String::from("小李"),
        age: 50,
    };
    e2.name = "金哲".to_string();
    println!(
        "Name is :{} company is {} age is {}",
        e2.name, e2.company, e2.age
    );

    // 实现方法
    impl Employee {
        fn plus(&mut self) {
            self.age += 1;
        }
        fn new(company: String, name: String, age: u32) -> Employee {
            return Employee {
                company: company,
                name: name,
                age: age,
            };
        }
    }
    let mut e3 = Employee::new("华为".to_string(), "李娜".to_string(), 30);
    e3.plus();
    println!("New age is {}", e3.age);
    e3.plus();
    println!("New age is {}", e3.age);
}
// 枚举
fn for_enum() {
    mark("枚举");
    #[derive(Debug)]
    enum Color {
        Blue,
        Green,
        Red,
    }
    println!("{:?}/{:?}/{:?}", Color::Blue, Color::Green, Color::Red);
}
// 模块
fn for_mod() {
    mark("模块");
    pub mod movies {
        pub fn play(name: String) {
            println!("Playing movie {}", name);
        }
    }
    movies::play("Herold and Kumar".to_string());
}
// 容器
// Rust 语言的容器标准库提供了最常见的通用的数据结构的实现。包括 向量 (Vector)、哈希表( HashMap )、哈希集合( HashSet ) 等等。
fn for_collections() {
    mark("容器 Vec");
    let mut v = Vec::new();
    v.push(20);
    v.push(30);
    v.push(40);
    v.remove(1); //删除索引==1
    if v.contains(&40) {
        println!("found 40");
    }
    for i in &v {
        //借用,要不后面不能用了
        println!("{}", i);
    }
    println!("size of vector is :{}", v.len());
    println!("{:?}", v);

    mark("容器 HashMap");
    // 哈希表 HashMap 就是 键值对 的集合
    let mut m = std::collections::HashMap::new();
    m.insert("name", "Zee"); //如果键已经存在,则更新为新的简直对,并则返回旧的值。
    m.insert("site", "https://zee.kim");
    m.insert("who", "balabala");
    m.remove(&"who"); //移除
    println!("{:?}", m);
    // 遍历
    for (key, val) in m.iter() {
        println!("key: {} val: {}", key, val);
    }
    // 是否存在
    if m.contains_key(&"name") {
        println!("found key");
    }
    match m.get(&"name") {
        Some(value) => {
            println!("Value for key name is {}", value);
        }
        None => {
            println!("nothing found");
        }
    }
    mark("容器 HashSet");
    // 没有重复值的相同数据类型的值的集合
    let mut s = std::collections::HashSet::new();
    s.insert("Python");
    s.insert("Rust");
    s.insert("Ruby");
    s.insert("PHP");
    s.insert("Rust"); // 插入失败但不会引发异常
    for language in s.iter() {
        println!("{}", language);
    }
    if s.contains(&"Rust") {
        println!("Contains found rust");
    }
    match s.get(&"Rust") {
        Some(value) => {
            println!("Match found {}", value);
        }
        None => {
            println!("Not found");
        }
    }
    s.remove(&"PHP");
    println!("{:?}", s);
}

// 错误处理
fn for_error() {
    // let f = std::fs::File::open("main.jpg");   // main.jpg 文件不存在
    // match f {
    //    Ok(f)=> {
    //       println!("file found {:?}",f);
    //    },
    //    Err(e)=> {
    //       println!("file not found \n{:?}",e);   // 处理错误
    //    }
    // }
    // 自定义错误信息
    // let f=std::fs::File::open("main.jpg").expect("error!");
    // println!("file found {:?}",f);
}
// 闭包
fn for_closure() {
    mark("闭包");
    let is_even = |x| x % 2 == 0;
    let no = 13;
    println!("{} is even ? {}", no, is_even(no));
}
// 智能指针
fn for_pointer() {
    mark("智能指针");
    let x = 5;           // 值类型数据,存在栈上
    let y = Box::new(x); // y 是一个智能指针,指向堆上存储的数据 5 
    println!("{}",5==x);
    println!("{}",5==*y); // 为了访问 y 存储的具体数据,需要解引用
}
// 线程
fn for_thread(){
    mark("线程");
	let mut pool = vec![];
	// 启动线程
	for i in 0..10 as i32 {
		pool.push(std::thread::spawn(move || println!("this is {}", i)));
	}
	// 返回一个结果
	for fish in pool {
		let _ = fish.join();
	}
}
// 标准输入
fn for_stdin(){
    mark("控制台输入");
    let mut line = String::new();
    println!("请输入你的名字:");
    let b1 = std::io::stdin().read_line(&mut line).unwrap();
    println!("你好 , {}", line);
    println!("读取的字节数为:{}", b1);
}
// 文件操作
fn for_file(){
    mark("文件操作"); 
    std::fs::write("data.txt", "2021-04-28").expect("could not write file");
    println!("写文件data.txt");
    let data = std::fs::read_to_string("data.txt").expect("could not read file");
    println!("读文件:{:?}",data);
    std::fs::copy("data.txt", "bar.txt").expect("could not copy file");
    std::fs::rename("bar.txt", "foo.txt").expect("could not rename file");
    println!("bar.txt=>foo.txt");
    std::fs::remove_file("foo.txt").expect("could not remove file");
    println!("foo.txt is removed");
    std::fs::create_dir_all("./abc").expect("could not create dir");
    println!("dir is created");
    std::fs::remove_dir_all("./abc").expect("could not remove dir");
    println!("dir is removed");
    std::fs::remove_file("data.txt").expect("could not remove file");
    println!("data.txt is removed");
    // 读取文件列表
    fn get_files(target:String) {
        let path = std::path::Path::new(&target);
        let entrys = std::fs::read_dir(path).expect("Failed to read src directory");
        for entry in entrys {
            if let Ok(entry) = entry {
                let dir = entry.path();
                let name = dir.to_str().unwrap();
                if name.contains(".DS_Store") {
                    continue;
                }
                // println!("{:?}", dir);
                if dir.is_file() {
                    println!("{}",name);
                }else{
                    get_files(name.to_string())
                }
            }
        }
    }
    get_files("./src/".to_string());
    
}

// 显示标题
fn mark(s: &str) {
    let left = "<".to_string().repeat(20);
    let right = ">".to_string().repeat(20);
    println!("{}", format!("{}{}{}", left, s.to_string(), right));
}