Rust从入门到劝退 ( 一 )

RUST 基础

主要是跟着B站上面的视频学习,代码和相关也是基本上跟着视频自己记下来
  1. cargo new xxx;cargo build;cargo run;cargo check(检查语法)

  2. 执行的文件在target的debug内

  3. 变量

    mut 可变变量

    隐藏,在同一个代码段同名变量定义时具有隐藏性,即第二次定义后使用的是使用的第二次定义的类型,将第一次定义的变量隐藏

    const 定义常量: const MAXX:u32 = 10000;

  4. 数据类型(编译器具有自动推导功能,不必须写上变量类型)

    bool型

    char型在rust语言里面是32位的!char可以是一个汉字

    i8 i16 i32 i64 u8 u16 u32 u64 f32 f64

    自适应类型(与机器平台有关系) isize usize println!("max = {}",usize::max_value());

    数组 [Type; size] size也是数组类型的一部分

    let arr: [u32; 5] = [1,2,3,4,5];
    show(arr);  // 这里会报错,因为size不一致而size也是数组类型的一个部分
    
    fn show(arr:[u32;3]){
        for i in &arr{
            println!("{}",i);
        }
    }
    

    元组 复合类型

    let tup: (i32,f32,char) = (-3,3.69,'赞');
    println!("{}",tup.0);
    println!("{}",tup.1);
    println!("{}",tup.2);
    let tup = (-3,3.69,'赞'); //自动推导
    //元组可拆解
    let (x,y,z) = tup;
    println!("{}",x);
    
  5. 函数 蛇形命名法 常量大写字母 类的首字母大写 一般函数等用小写字母

    fn other_fun(){
    	println!("This is a function!");
    }
    fn other_fun1(a:i32,b:u32){
        println!("a = {},b = {}",a,b);
    }
    fn other_fun2(a:i32,b:i32) -> i32{
        let result = a + b;
        return result;
    }
    fn other_fun3(a:i32,b:i32) -> i32{
        a + b
    }
    

    函数定义的时候传入的变量需要有类型

  6. 语句 执行操作 但是不返回值得指令

    let y = 1; //语句,不返回值
    let x = (let y = 1);  //错误的,因为无返回值,与C++不一样
    

    表达式 会计算一些值

    let y = {
    	let x = 1;
        x + 1; //错误 无发返回
    	x + 1 //正确,输出y为2
    }
    
  7. 控制流

    ​ println!("y==other");

    if y == 1 {
    	println!("y==1");
    }else{
        println!("y!=1");
    }
    if y == 1 {
    	println!("y==1");
    }else if y == 0{
        println!("y==0");
    }else{
        println!("y==other");
    }
    

    let中也可以使用if,且if else中得类型应该保持一致

    let condition = true;
    let x = if condition{
    	5
    }else{
    	6
    };
    println!("{}",x);
    

    loop loop 也可以赋值给let

    let mut counter = 0;
    loop{
    	println!("loop");
    	if counter == 10{
    		break;
    	}
    	counter = counter + 1;
    }
    let mut c = 1;
    let result = loop{
        c += 1;
        if c == 20{
            break c * 2;
        }
    };
    println!("{}",result); //result为40
    

    while 循环

    let mut i = 0;
    while i !=10 {
    	i += 1;
    }
    println!("i={}",i);
    

    for 循环

    let arr:[u32;5] = [1,2,3,4,5];
    //用迭代器
    for element in &arr{
    	println!("element={}",element);
    }
    
  8. 所有权

    1. 堆和栈

      编译的时候数据的类型大小是固定的,就是分配在栈上的

      编译的时候数据的类型大小不是固定的,就是分配在堆上的

    2. 作用域: {}

      let x:i32 = 1;
      {
      	let y:i32 = 2;
      	println!("{}",x);
      }
      println!("{}",y);
      // y的作用域在{}之内,因此下面无法访问到y的值
      
    3. 借用/移动

      let s1 = String::from("abc");
      let s2 = s1;
      println!("{}",s1);//报错
      

      类似于C++中的浅拷贝,只是对指针复制,没有对指针所指的区域的进行复制

      RUST中拷贝后默认s1无效,即s1的所有权移植给了s2,因此s1处于空,无效状态

      同时RUST中string存在内存回收,在离开作用域时会自动调用drop完成内存的回收操作,类似于类的析构

    4. clone/深拷贝

      let s1 = String:from("abc");
      let s2 = s1.clone();
      

      再访问s1可以访问,clone可以拷贝数据即进行深拷贝

    5. 栈上的数据拷贝

      let a = 1;
      let b = a;
      println!("a = {} , b = {}",a,b);
      

      在栈上的数据执行等号的时候默认进行copy(相当于深拷贝)

      类似于C++中int char等相等之后也可以用,但是class类需要自定义深拷贝clone函数

    6. 常用的具有copy trait有

      所有的整型 浮点型 布尔型 字符类型(char) 元组 数组

    7. 函数和作用域

      fn fun(some_string: String){
          println!("{}",some_string);
      }
      fn fun2(i:i32){
          println!("i = {}",i);
      }
      
      fn main(){
          let s = String::from("hello");
          fun(s);
          println!("{}",s);//报错 S已经在离开作用域的时候被drop回收了
          let x = 5;
          fun2(x);
          println!("{}",x); //可以使用,x分配在栈上,是直接进行copy而不是clone
      }
      
  9. 引用和借用

    fn main(){
    	let s1 = gives_ownership();
        let s2 = String::from("hello");
        let s3 = takes_and_gives_back(s2);
        
        println!("Hello world!");
    }
    fn gives_ownership() -> String {
        let s = String::from("hello");
        s
    }
    fn takes_and_gives_back(s: String) -> String {
        s
    }
    

    因为是调用gives_ownership函数,因此调用后将s的作用域返回给s1

    因为s2的使用权将传递给s3,所以如果在最后再次调用s2会发现无法使用

    会发现上面十分麻烦,所以RUST中存在了引用这个功能

    // 引用: 用法&,
    // 让我们创建一个指向值的应用,但是并不拥有它,因为不拥有这个值,所以,当引用离开其值指向的作用域后也不会被丢弃
    // 借用:&mut
    fn length(s: &String) -> usize{
        s.len()
    }
    fn modify_s(s: &mut String){
        s.push_str(",world");
    }
    fn main(){
        let mut s1 = String::from("hello");
        let len = length(&s1);
        let s = &s1;
        println!("s = {}",s);
        println!("s1 = {}",s1);
        println!("len = {}",len);
        modify_s(&mut s1);
        println!("s1 = {}",s1);
    }
    

    引用无法对值进行修改,只是可以去完成访问,如果需要修改一类操作,需要借用

    RUST推荐每个变量只有一个数据拥有权(引用or借用),即不可变引用和可变借用不可以针对于同一个变量同时存在,也就是可读和可读可写不能同时存在

    但是当我对其中某一个运用完后可以调用另外一个,即可变以后要重新去进行借用,示例代码如下

    fn main(){
        let mut s = String::from("hello");
        let s1 = &s;
        println!("{}",s1);
        let s2 = &mut s;
        s2.push_str(",world!");
        println!("{}",s2);
    }
    

    泉水引用 Wrong

    fn main(){
    	let ref_s = dangle();
    }
    fn bcyx() -> &String{
    	let s = String::from("hello");
    	&s 
    }
    

    作用域在函数内回收掉了,但是引用仍然指向内存,并且返回引用,会报错

  10. slice

    let s = String::from("hello world!");
    let h = &s[0..5];
    let h = &s[..5];
    let h = &s[0..=4];
    let h = &s[..=4];
    let w = &s[6..];//第六位到结尾
    let a = [1,2,3,4];
    let sss = &a[1..3];
    println!("sss1 = {}",sss[0]);
    println!("h = {}",h); //输出hello 上面四个情况均一致
    
  11. 结构体

    1. 定义结构体

       #[derive(Debug)]
          struct User {
              name: String,
              count:String,
              nonce: u64,
              active: bool,
          }
      
    2. 创建结构体实例

          let xiaoming = User {
              name: String::from("xiaoming"),
              count: String::from("80001000"),
              nonce: 10000,
              active:true,
          };
          println!("xiaoming = {:?}", xiaoming);//横着打出来
          println!("xiaoming = {:#?}", xiaoming);//结构体
      
    3. 修改结构体字段

          let mut xiaohuang = User {
              name: String::from("xiaohuang"),
              count: String::from("80001000"),
              nonce: 10000,
              active:true,
          };
      	xiaohuang.nonce = 20000;
      
    4. 参数名字和字段名字同名的简写方法

      let name = String::from("xiaoxiao");
      let count = String::from("89077777");
      let nonce = 200000;
      let active = false;
      let user1 = User {
          name,
          count,
          nonce,
          active,
      };
      
    5. 从其他结构体创建实例

      let user2 = User {
          name: String::from("user2"),
          ..user1
      };
      println!("name = {}", user2.name);
      println!("nonce = {}", user2.nonce);
      
    6. 元组结构体

      //(1)字段没有名字直接.0和.1等
      //(2)圆括号
      struct Point(i32, i32);
      
      let a = Point(10, 20);
      let b = Point(30, 11);
      
      println!("a.x = {}, a.y = {}", a.0, a.1);
      
    7. 没有任何字段的类单元结构体

      struct A{};
      
    8. 打印结构体

      //结构体前添加  #[derive(Debug)]
      # [derive(Debug)]
      println!("xiaoming = {:?}",xiaoming); //横着打印出来
      println!("xiaoming = {:#?}",xiaoming) //自动换行打印
      
  12. 方法

    # [derive(Debug)]
    struct Dog {
        name: String,
        weight: f32,
        height: f32,
    }
    //简单理解成C++中的类函数
    impl Dog {
        fn get_name(&self) -> &str {
            &(self.name[..])
        }
    
        fn get_weight(&self) -> f32 {
            self.weight
        }
    
        //fn get_height(&self) -> f32 {
        //    self.height
        //}
    
        fn show() {
            println!("oh oh oh");
        }
    }
    
    impl Dog{
        fn get_height(&self) -> f32 {
            self.height
        }
    }
    
    fn main() {
        let dog = Dog {
            name: String::from("wangcai"),
            weight: 100.0,
            height: 70.5,
        };
    
        println!("dog = {:#?}", dog);
        println!("name = {}", dog.get_name());
        println!("weight = {}", dog.get_weight());
        println!("height = {}", dog.get_height());
    
        Dog::show();
    
        println!("Hello, world!");
    }
    
  13. 枚举类型与模式匹配

    //1、类似于c语言的方式定义
    enum IpAddrKind {
        V4,
        V6,
    }
    
    struct IpAddr {
        kind: IpAddrKind,
        address: String,
    }
    
    //2、rust语言提倡的方式定义
    enum IpAddr2 {
        V4(String),
        V6(String),
    }
    
    //3、可以是不同类型
    enum IpAddr3 {
        V4(u8, u8, u8, u8),
        V6(String),
    }
    
    //4、经典用法
    enum Message {
        Quit,
        Move{x: i32, y: i32},
        Write(String),
        Change(i32, i32, i32),
    }
    
    //等同于
    //struct QuitMessage; //类单元结构体
    //struct MoveMessage {
    //  x: i32,
    //  y: i32,
    //}
    //struct WriteMessage(String) 
    //struct Change(i32, i32, i32)
    
    //5、枚举类型的方法以及match
    impl Message {
        fn prin(&self) {
            match *self {
                Message::Quit => println!("Quit"),
                Message::Move{x, y} => println!("Move x = {}, y = {}", x, y),
                Message::Change(a, b, c) => println!("Change a = {}, b = {}, c = {}", a, b, c),
                _ => println!("Write")
                //Message::Write(&s) => println!("Write = {}", s)
            }
        }
    }
    
    fn main() {
        let i1 = IpAddr {
            kind: IpAddrKind::V4,
            address: String::from("127.0.0.1"),
        };
    
        let i2 = IpAddr {
            kind: IpAddrKind::V6,
            address: String::from("::1"),
        };
    
        let i1 = IpAddr2::V4(String::from("127.0.0.1"));
        let i2 = IpAddr2::V6(String::from("::1"));
    
        let i1 = IpAddr3::V4(127, 0, 0, 1);
        let i2 = IpAddr3::V6(String::from("::1"));
    
        let quit = Message::Quit;
        quit.prin();
    
        let mo = Message::Move{x: 10, y: 20};
        mo.prin();
    
        let wri = Message::Write(String::from("Hello"));
        wri.prin();
    
        let change = Message::Change(1, 2, 3);
        change.prin();
        println!("Hello, world!");
    }
    
  14. Option

    option是标准库定义的一个枚举类型

    match一定要处理完Option中所有的情况

    enum Option<T> {
    	Some(T),
    	None,
    }
    
    fn main(){
        let some_number = Some(5);
        let some_string = Some(String::from("123"));
        let absent_number: Option<i32> = None;
        
        let x:i32 = 5;
        let y:Option<i32> = Some(5);
        let mut temp:i32 = 0 
        // let sum = x + y; x和y不是同一个类型
        match y{
            Some(i) => {temp = i ;}
            None => {println!("No");}
        }
        let sum = x + temp;
        let result = plus_one(y);
        match result {
            Some(i) => println!("result = {}", i),
            None => println!("nothing"),
        };
        println!("sum = {}",sum);
    
        if let Some(value) = plus_one(y) {
            println!("value = {}", value);
        }
    
        
        if let Some(value) = plus_one(y) {
            println!("value = {}", value);
        } else {
            println!("do nothing");
        }
    }
    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(x) => Some(x+1),
        }
    }
    
  15. Vector

    fn main(){
        // 1. 创建空的vector
        let mut v:Vec<i32> = Vec::new();
        v.push(1);
        // 2. 创建包含初始值的vector
        let v = vec![1,2,3];
        // 3. 丢弃vector
        {
            let v1 = vec![1,2,3];
        }
        // 4. 读取元素
        let one: &i32 = &v[1];
        println!("{}",one);
        println!("{}",*one);
        //上面这两种输出的形式一样 应该是存在自动转换功能
        
        match v.get(1){
            Some(Value) => println!("value = {}",value),
            _ => None,
        }
        // 5. 更新
        let mut v2:Vec<i32> = Vec::new();
        v2.push(1);
        v2.push(2);
        v2.push(3);
        // 6. 遍历
        // 不可变的遍历
        for i in &v2{
            println!("{}",i);
        }
        // 可变的遍历
        for i in &mut v2{
            *i += 1;
            println!("{}",i);
        }
        // 7. 使用枚举
        enum Context {
            Text(String),
            Float(f32),
            Int(i32),
        };
    
        let c = vec![
            Context::Text(String::from("string")),
            Context::Int(-1),
            Context::Float(0.001)
        ];
        
        // 8. 补充
        let mut v = vec![1, 2, 3, 4, 5];
        let first = &v[0];
        
        v.push(6);
        //报错!!!!
        //不可变引用后使用可变引用不能再使用不可变引用了!!!!
        println!("first = {}", first);
    
        println!("Hello, world!");
    }
    
  16. String

    //1、创建一个空String
    //2、通过字面值创建一个String
    //2.1、使用String::from()
    //2.2、使用str的方式
    //3、更新String
    //3.1、push_str
    //3.2、push
    //3.3、使用“+”合并字符串
    //3.4、使用format!
    //4、String 索引
    //5、str 索引
    //6、遍历
    //6.1、chars
    //6.2、bytes
    fn main() {
        let mut s0 = String::new();
        s0.push_str("hello");
        println!("s0 = {}", s0);
    
        let s1 = String::from("init some thing");
        println!("{}", s1);
    
        let s1 = "init some thing".to_string();
        println!("{}", s1);
    
        let mut s2 = String::from("hello");
        s2.push_str(", world");
        let ss = " !".to_string();
        s2.push_str(&ss);//用ss的引用
        println!("{}", s2);
        println!("ss = {}", ss);
    
        let mut s2 = String::from("tea");
        s2.push('m');
        //s2.push('mx'); //error
        //s2.push("x");  //error
        println!("{}", s2);
    
        let s1 = "hello".to_string();
        let s2 = String::from(", world");
        let s3 = s1 + &s2;
        println!("s3 = {}", s3);
        //println!("s1 = {}", s1);
        println!("s2 = {}", s2);
    
        let s341 = String::from("tic");
        let s342 = String::from("tac");
        let s343 = String::from("toe");
        let s344 = format!("{}-{}-{}", s341, s342, s343); //format!和println!类似
        println!("s344 = {}", s344);
        println!("s341 = {}", s341);
        println!("s342 = {}", s342);
        println!("s343 = {}", s343);
    
        let s4 = String::from("hello");
        //let s41 = s4[0];
        println!("s4.len = {}", s4.len());
        
        let s4 = String::from("你好");
        println!("s4.len = {}", s4.len());
        //let s41 = s4[0];
    
        let hello = "你好";
        let h5 = &hello[0..3];
        println!("h5 = {}", h5);
    
        //let h6 = &hello[0..2];
        //println!("h6 = {}", h6);
    
        //chars
        for c in s4.chars() {
            println!("c = {}", c);
        }
    
        println!("+++++++++++++++");
        //bytes
        for b in s4.bytes() {
            println!("b = {}", b);
        }
        println!("+++++++++++++++");
        println!("Hello, world!");
    }
    
  17. HashMap

    //1、HashMap<K, V>
    //2、创建HashMap
    //3、读取
    //4、遍历
    //5、更新
    use std::collections::HashMap;
    
    fn main() {
        let mut scores: HashMap<String, i32> = HashMap::new();
        scores.insert(String::from("Blue"), 10);
        scores.insert(String::from("Red"), 20);
    
        let keys = vec![String::from("Blue"), String::from("Red")];
        let values = vec![10, 20];
        let scores: HashMap<_, _> = keys.iter().zip(values.iter()).collect();
    
        let k = String::from("Blue");
        if let Some(v) = scores.get(&k) { //get 返回的是一个Option
            println!("v = {}", v);
        }
    
        let k = String::from("Yellow");
        let v = scores.get(&k);
        match v {
            Some(value) => println!("v = {}", value),
            None => println!("None"),
        }
    
        println!("++++++++++++");
        //遍历:会以任意的顺序遍历出来
        for (key, value) in &scores {
            println!("{}, {}", key, value);
        }
        println!("++++++++++++");
    
        //直接插入
        let mut ss = HashMap::new();
        ss.insert(String::from("one"), 1);
        ss.insert(String::from("two"), 2);
        ss.insert(String::from("three"), 3);
        ss.insert(String::from("one"), 3);//覆盖前者
        println!("{:?}", ss);
    
        //键不存在的时候才插入
        let mut ss1 = HashMap::new();
        ss1.insert(String::from("one"), 1);
        ss1.insert(String::from("two"), 2);
        ss1.insert(String::from("three"), 3);
        ss1.entry(String::from("one")).or_insert(3);
        println!("ss1 = {:?}", ss1);
    
        //根据旧值来更新一个值
        let text = "hello world wonderful world";
        let mut map = HashMap::new();
        for word in text.split_whitespace() {
            let count = map.entry(word).or_insert(0);
            *count += 1;
        }
        println!("map = {:?}", map);
    
        println!("Hello, world!");
    }
    
    
  18. 模块

    1. 定义

      1. 包:Cargo的一个功能,允许构建、测试和分享crate
      2. Crate:一个模块的树形结构,形成库或二进制项目
      3. 模块:通过use来使用,用来控制作用域和路径的私有性
      4. 路径
    2. 包和crate

      1. crate root是一个源文件,起点
      2. crate root是src/main.rs或者src/lib.rs,如果只有main.rs说明只有一个crate
      3. crate将一个作用域的相关功能分组,可以实现多个项目之间的共享
      mod factory {
          pub mod produce_refrigerator {
              pub fn produce_re() {
                  println!("produce refrigerator!");
              }
          }
      
          mod produce_washing_machine {
              fn produce_washing() {
                  println!("produce washing machine!");
              }
          }
      }
      
      fn main() {
          factory::produce_refrigerator::produce_re();
      
          println!("Hello, world!");
      }
      
  19. 模块2

    创建好的项目里cargo new --lib mylib

    //factory.rs
    pub mod produce_refrigerator {
        pub fn produce_re() {
            println!("produce refrigerator!");
        }
    }
    
    pub mod produce_washing_machine {
        pub fn produce_washing() {
            println!("produce washing machine!");
        }
    
        pub fn produce_re() {
            println!("produce washing machine!");
        }
    }
    
    //lib.rs
    pub mod factory;
    

    先在main的cargo里面添加

    [dependencies]
    mylib = {path = "./mylib"}
    

    在main.rs中利用

    //use mylib::factory::produce_refrigerator;
    //use mylib::factory::produce_refrigerator::produce_re;
    //use mylib::factory::produce_washing_machine;
    //use mylib::factory::produce_washing_machine as A;
    
    use mylib::factory::*;
    
    fn main() {
        mylib::factory::produce_refrigerator::produce_re(); //绝对路径
        produce_refrigerator::produce_re();  //使用use
        produce_washing_machine::produce_re();
        //A::produce_re();
    
        println!("Hello, world!");
    }
    
  20. 模块3

    mod modA {
        #[derive(Debug)]
        pub struct A {
            pub number: i32,
            name: String,
        }
    
        impl A {
            pub fn new_a() -> A {
                A {
                    number: 1,
                    name: String::from("A"),
                }
            }
    
            pub fn print_a(&self) {
                println!("number: {}, name: {}", self.number, self.name);
            }
        }
    
        pub mod modB {
            pub fn print_B() {
                println!("B");
            }
    
            pub mod modC {
                pub fn print_C() {
                    println!("C");
                    super::print_B();
                }
            }
        }
    }
    
    //use modA::A;
    use modA::A as A1;
    fn main() {
        //let a = modA::A::new_a();
        //let a = A::new_a();
        let a = A1::new_a();
        a.print_a();
    
        let number = a.number;
        //let name = a.name;
    
        println!("+++++++++++++");
        modA::modB::modC::print_C();
        println!("Hello, world!");
    }
    
  21. 模块4

  22. 错误1

    //1、rust语言将错误分为两个类别:可恢复错误和不可恢复错误
    //(1)可恢复错误通常代表向用户报告错误和重试操作是合理的情况,例如未找到文件。rust中使用Result<T,E>来实现。
    //(2)不可恢复错误是bug的同义词,如尝试访问超过数组结尾的位置。rust中通过panic!来实现。
    
    //2、panic!
    
    //3、使用BACKTRACE=1
    
    //4、Result<T, E>
    //enum Result<T, E> {
    //  Ok(T),
    //  Err(E),
    //}
    
    //5、简写
    use std::fs::File;
    fn main() {
        //let f = File::open("hello.txt");
        //let r = match f {
        //    Ok(file) => file,
        //    Err(error) => panic!("error: {:?}", error),
        //};
    
    
        //let f = File::open("hello.txt").unwrap();
        let f = File::open("hello.txt").expect("Failed to open hello.txt");
        //panic!("crash here");
    }
    
  23. 错误2

    //1、当编写一个函数,但是该函数可能会失败,此时除了在函数中处理错误外,还可以将错误传给调用者,让调用者决定如何处理,这被称为传播错误。
    //2、传播错误的简写方式,提倡的方式
    //3、更进一步的简写
    //4、什么时候用panic!,什么时候用Result
    //(1)示例、代码原型、测试用panic!\unwrap\expect
    //(2)实际项目中应该用Result
    //5、Option和Result
    
    use std::io;
    use std::io::Read;
    use std::fs::File;
    fn main() {
        println!("Hello, world!");
        let r = read_username_from_file();
        match r {
            Ok(s) => println!("s = {}", s),
            Err(e) => println!("err = {:?}", e),
        }
    }
    
    //fn read_username_from_file() -> Result<String, io::Error> {
    //    let f = File::open("hello.txt");
    //    let mut f = match f {
    //        Ok(file) => file,
    //        Err(error) => return Err(error),
    //    };
    //
    //    let mut s = String::new();
    //    match f.read_to_string(&mut s) {
    //        Ok(_) => Ok(s),
    //        Err(error) => Err(error),
    //    }
    //}
    //
    //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)
    //}
    
    fn read_username_from_file() -> Result<String, io::Error> {
        let mut s = String::new();
        File::open("hello.txt")?.read_to_string(&mut s)?;
        Ok(s)
    }
    
上一篇:Rust IO 操作简介


下一篇:【Rust日报】 2019-05-30:使用最新的 async/await 的一些例子