Rust第一版笔记

161 阅读10分钟
  1. let的作用是什么?在rust中,let定义的变量为不可变变量 . 定义变量时如果没有定义类型,会进行类型推导。如果明确指定类型则告诉编译器该变量的类型。

    let food = faster;
    let food:String faster = "string";
    
  2. mut的作用是什么?mut表示当前变量是可变的。也就是可以将变量的所有权进行移动的。

  3. 什么是关联函数?没有self参数的函数。关联函数一般用于构建对象,因为对象还没有创建时没有&self对象。


    struct Person {
        name: String,
        age: i32,
    }

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

  1. 在局部作用域中,可以定义多个相同变量名的变量,后一个变量会覆盖前一个变量,该种特性叫隐藏。该特性常用于转换值类型的场景。隐藏机制
    let name = "zhangsan";
    let name = "lisi";//name会隐藏掉上面值为张三的变量

  1. loop用于循环,类似于 while(true){ }

use std::cmp::Ordering;
//use 关键字用于将外部的模块、类型、函数、常量等引入当前作用域,
// 以便在代码中更方便地访问它们,而不需要使用完整的路径。
use std::io;
use rand::Rng;
fn main() {
    println!("Guess the number");

    let secret_number = rand::thread_rng()
        .gen_range(1..101);
    println!("The secret number is: {}", secret_number);
    //let:创建一个变量如:let  foo = bar;创建的变量默认是不可变的
    //mut:修饰变量为可变的


    loop {
        println!("Please input you guess:");
        let mut guess = String::new();
        //&mut:
        io::stdin().read_line(&mut guess)
            .expect("Failed to read line");
        println!("You guessed:{}", guess);
        let guess: u32 = guess.trim().parse()
            .expect("parse error");
        match guess.cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("You win!");
                break;
            }
        }
    }
}
  1. match的作用是什么 类似于when的匹配;
  2. 使用多级mut修改变量
fn main() {
    let mut a = 10;

    let mut x = &mut a;
    println!("x == {}", x);
    modify_x(&mut x);
    println!("x == {}", x);
}

fn modify_x(x: &mut &mut i32) {
    **x = 20;
}

  1. 什么是常量,使用const进行标注常量,常量声明需要类型标注; 常量是不可变的,而且是永远不可变的。变量是不可变的,但是通过mut修饰的变量是可以变的。(mut是否可以理解为取地址操作?,而const修饰的则表示该变量不能通过取地址的方式去修改变量执行的内存空间)

  2. 类型和类型标注是什么?常量总需要类型标注。

    类型标注是显式地为变量或常量指定类型。

  3. 整数溢出是什么?当类型为u8类型时,赋值范围在0-255区间,如果赋值超过该区间则为整数溢出。在debug模式下会包含整数溢出的检测代码,并触发panic异常。如果在release模式下则会执行补码环绕。如果通过补码环绕功能实现逻辑是,建议使用Wrapping类型。

  4. 不可恢复错误和painc;

  5. rust中的bool类型。

  6. rust中的字符类型为char;

  7. 什么是符合类型?rust提供了元组和数组两种符合类型。

 let tuple:(u8,u32,f32) = (23,555,2.32);元组中每个类型的数据可以不一样。
 println!("value 0 = {}",tuple.0);
 println!("value 1 = {}",tuple.1);
 println!("value 2 = {}",tuple.2);

 //解构
 let tuple:(u8,u32,f32) = (23,555,2.32);元组中每个类型的数据可以不一样。
 let (a,b,c) = tuple;
  1. rust中创建数组的几种方法
        //定义非动态数组
        let arr = [1,2,4,45,5];
        //定义大小为6,类型为u8的数组,数组中实际的值只有4个,其他值默认为0.
        let arr1:[u8,6] = [1,2,4,5];
        //创建大小为5,默认初始值为3的数组
        let  arr2 = [3;5];
    
    
  2. rust中函数的命名规则为蛇形命名规则,fun_tx_xx(){ };
  3. 表达式和语句,语句没有返回值,表达式有返回值。
  4. 函数的返回值
    fn function()->u8{
    
    return 1;
    }
    
    fn function()->u8{
    
     1//最后一行表示返回值
    }
    //这种情况下,默认会返回一个空元组,但是返回的类型确实u8,所以会报错。
    //第二个,编译器会建议remove掉;分号
    fun function()->u8{
        2;
    }
    

19.控制流

    let num = 3;
    if num > 6 {
        //todo    
    } else {
        //todo
    }
    
    let res = if num > 4 { 4 } else { 19 }
    
  1. loop用于循环和返回值
    let mut counter = 2;
    let result = loop{
        if counter == 2 {
            break conunter * 2;
        }
    }

  1. for循环遍历数组
    fn main(){
        let arr = [1,2,4,5,6,7];
        for element in arr.iter() {
            println!("element value {}",element);
        }
    
    }

  1. 所有权重,切片,引用,借用,移动
  2. String在堆上创建的方式 String::from("hello world!");
  3. 移动的示例
    let s1 = String::from("hai");
    let s2 = s1;//这里发生了移动
    println!("s1 === {}",s1);//这里是不合法的,因为s1发生了移动,导致s1变量已经失效了。
    let s3 = s2.clone();//这里产生了克隆,该行为不会导致s2失效
    println!("s2 === {}",s2);//这里是合法的
    
  1. 在rust中,如果实现了Copy的trait后,则不能实现Drop的trait。
  2. 任何需要分配资源和内存的都不是Copy类型,如果元组中的每一项都是Copy类型的,则该元组也是Copy类型。
  3. 移动,需要分配内存和资源的类型才才支持移动,移动表示所有权发生了变化。
  4. 只有所有权发生改变时,才会执行drop函数。
  5. 引用类型和解引用,使用&String表示一个String类型的引用。通过引用传递参数给函数的方法也被称为借用。借用是不能对变量进行修改的,只有拥有所有权才能对数据进行修改。
  6. 可变引用:函数定义fn change(some_string: &mut String).可变引用一次只能声明一个可变引用
  7. 数据竞争:data race,数据竞争指的是多个指向同一块内存的指针对数据进行操作导致的竞争。
  8. 不可变引用和可变引用不能同时存在,原因为不可变引用不希望在眼皮底下数据发生了改变。但是多个不可变引用可以同时存在,因为不会对数据进行写操作。
  9. 切片:slice允许我们引用集合中某一段连续的序列,而不是整个集合。
  10. 字符串字面量就是就是切片,&str,&str是一个不可变的引用,所以字符串字面量才是不可变。
  11. 结构体的定义
       struct User{
           name:String,
           email:String,
           active:bool,
           sign_in_count:u64,
       }

        let user1 = User {
            email: String::from("someone@example.com"),
            username: String::from("someusername123"),
            active: true,
            sign_in_count: 1,
        };
       fn build_user(name:String,email:String){
           User{
               name:name,
               email:email,
               active:True,
               sign_in_count:1,
           }
       }
       //修改字段,如果当前对象为mut类型,则所有的字段都是可变类型。
       let mut user = build_user(String::from("Hello"),String::from("tag@ggmai.com"));
       user.name = String::from("zhangsan");
       
       //另一种copy的方式
       
        let user2 = User {
            email: String::from("another@example.com"),
            username: String::from("anotherusername567"),
            ..user1
        };
  1. 元组结构体
        struct Color(u8,u8,u8);
        let color = Color(144,134,138);
    
  2. 枚举

    enum Coin { Penny,
        Nickel,
        Dime,
        Quarter,


    }


    fn value_in_cents(coin: Coin) -> u32 { 
        match coin {
         Coin::Penny => 1, 
         Coin::Nickel => 5, 
         Coin::Dime => 10, 
         Coin::Quarter => 25,

        } 
  }
  1. 枚举实例
//这个是为了支持打印
#[derive(Debug)]
enum UsState {
    Alabama,
    Alaska,
    Arizona,
    Arkansas,
    California,
}
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter(UsState),
}

fn main() {
    let coin = Coin::Quarter(UsState::California);
    let coin = Coin::Dime;
    match coin {
        Coin::Penny => println!("Lucky penny!"),
        Coin::Nickel => println!("Lucky nickel!"),
        Coin::Dime => println!("Lucky dime!"),
        Coin::Quarter(state) => println!("Lucky quarter from {:?}", state),
    }
}
  1. 枚举+1

fn main() {
    let x: Option<i32> = Some(5);
    let y: Option<i32> = None;
    let z = plus_one(x);
    let w = plus_one(y);
    println!("{:?}", z);
}

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        Some(n) => Some(n + 1),
        None => None,
    }
}
  1. 匹配必须穷举所有的可能
    fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {//编译不通过
        Some(n) => Some(n + 1),
    }
}

41._ 通配符

    //通配符
    let numbers = 4;
    match numbers {
        0 => println!("zero"),
        1 | 2 | 3 => println!("one, two, or three"),
        _ => println!("something else"),
    }
  1. if let 可以只处理只关心的一种case
    //if let
    let numbers = Some(3);
    if let Some(3) = numbers {
        println!("three")
    }
  1. trait是什么? 类似于java中的接口。


trait OptionExt {
    fn expect(self, msg: &str) -> Self;
    fn unwrap(self) -> Self;
    fn unwrap_or(self, default: Self) -> Self;
}

impl<T> OptionExt for Option<T> {
    fn expect(self, msg: &str) -> Self {
        match self {
            Some(v) => v,
            None => panic!(msg),
        }
    }

    fn unwrap(self) -> Self {
        match self {
            Some(v) => v,
            None => panic!("called `Option::unwrap()` on a `None` value"),
        }
    }

    fn unwrap_or(self, default: Self) -> Self {
        match self {
            Some(v) => v,
            None => default,
        }
    }
}
  1. crate是什么?在rust中为包的意思。只有src/main.rs的为二进制包,如果只有src/libs.rs的为库单元包。一个crate最少有一个二进制包或者一个库单元包。一个crate可以有多个二进制包,最多一个库单元包。如果是多个二进制单元包,则这些单元包放在src/bin下面。每个文件为一个二进制单元包。
  2. use的作用?use是将路径引入到作用域中的关键字。
  3. pub的作用?pub是将条目标记为公开的。在rust中所有的mod默认都是private的。子模块可以访问父模块中的内容,但父模块不能访问子模块中的内容。
  4. mod的作用是什么?mod的作用是用来定义moudle的。默认moudle为private。需要使用pub修饰才能被外部访问。
  5. 关于访问权限,在同级别中可以直接访问,在子级中可以访问父级的private内容。
  6. crate用于指定绝对路径。
  7. super用于指定相对路径。
fn server_order() {
    println!("The chef is preparing your order.");
}
mod back_of_house {
    fn fix_incorrect_order() {
        println!("The kitchen is fixing your order.");
        cook_order();
        super::server_order();
    }
    fn prepare_table() {
        println!("The bartender is preparing your table.");
    }
    fn cook_special_dish() {
        println!("The chef is cooking your special dish.");
    }
    fn cook_order() {
        println!("The kitchen is cooking your order.");
    }
}
  1. 在rust中如何在mod中将结构体,枚举声明为pub。
mod back_of_house {
    pub struct Breakfast {
        pub toast: String,
         seasonal_fruit: String,
    }
    impl Breakfast {
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: String::from(toast),
                seasonal_fruit: String::from("peaches"),
            }
        }
    }
}

pub fn eat_at_restaurant() {
    let mut meal = back_of_house::Breakfast::summer("wheat");
    println!("I'm eating {} toast", meal.toast);
    meal.toast = String::from("whole wheat");
    //seasonal_fruit is private, so we can't access it directly
    println!("I'm eating {} toast with {} seasonal fruit.", meal.toast, meal.seasonal_fruit);
}
  1. 将枚举修饰为pub,则其所有的变体都是pub的状态。
  2. use和Self
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}
use self::front_of_house::hosting;
pub fn eat_at_restaurant() {
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
    hosting::add_to_waitlist();
}
  1. 如何解决路径相同的情况?
    1. 使用as将名字进行修改。
    use std::fmt::Result;
    use std::io::Result as IoResult;
    
    1. 使用pub use重新导出名字
        mod front_of_house {
            pub mod hosting {
                pub fn add_to_waitlist() {}
            }
        }
        pub use crate::front_of_house::hosting;
        pub fn eat_at_restaurant() {
            hosting::add_to_waitlist();
            hosting::add_to_waitlist();
            hosting::add_to_waitlist();
        }
    
  2. 如何简化use导入?use std::{cmp::Ordering, io};
    use std::io;
    use std::io::Write;

    //如下方式简化
    use std::io::{self, Write};
  1. 在使用use的通配符

    use std::collections::*;
    
  2. 将模块拆分到不同的文件中

  3. 错误传播 panic和Result错误

  4. 向外抛出Resut异常

    use std::io;
    use std::io::Read;
    use std::fs::File;
    fn read_username_from_file() -> Result<String, io::Error> {
        let f = File::open("hello.txt");
        let mut f = match f {
            Ok(file) => file,
            Err(e) => return Err(e),
        };
        let mut s = String::new();
        match f.read_to_string(&mut s) {
            Ok(_) => Ok(s),
            Err(e) => Err(e),
        }
    }
  1. 使用?问号符号将异常简化
    use std::io;
    use std::io::Read;
    use std::fs::File;
    fn read_username_from_file() -> Result<String, io::Error> {
        let mut f = File::open("hello.txt")?;
        let mut s = String::new();
        f.read_to_string(&mut s)?;
        Ok(s)
    }

64.触发panic的快捷方式unwrap expect

    use std::fs::File;

    fn main() {
        let f = File::open("hello.txt").unwrap();
    }
  1. main函数默认返回的是空元组,也可以返回Result<T,E>类型;Box<dyn Error>成为trait对象
    fn main()->Result<(),Box<dyn Error>>{
        let f = File::open("xxx.txt");
        
        Ok(())
        
    }
  1. 泛型,和java中的类型
  2. trait约束
 pub fn notify<T: Summary>(item: T) {
     println!("Breaking news! {}", item.summarize());


 }
 ```
 
68. 实现多个trait

```rust
pub fn notify(item: impl Summary + Display) {


pub fn notify<T: Summary + Display>(item: T) {

  1. 使用impl约束多个trait
pub fn notify(item1: impl Summary, item2: impl Summary) {

pub fn notify<T: Summary + Display>(item: T) {

pub fn notify(item: impl Summary + Display) {

70.使用where简化trait约束

fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {

fn some_function<T, U>(t: T, u: U) -> i32
    where T: Display + Clone,
    U: Clone + Debug
{