Published on

Rust入门笔记(二)

Authors
  • avatar
    Name
    Et cetera
    Twitter

Rust 变量常量&数据类型

Rust 使用 let 声明变量

变量就先不陈述了,老生常谈,学习各种语言都会说一遍变量

使用 let 声明的变量默认是不可变的

fn main() {
    let band = "one ok rock";

    band = "aimyon";
}

上侧代码cargo run会报错如下(当然还有个问题,就是 band 变量声明但未使用)

解决方法:使用mut(mutable)关键字

fn main() {
    let mut band = "one ok rock";

    // 同时字符串占位这方面类似于 Python
    println!("hello {}", band);

    band = "aimyon";

    println!("hello {}", band);
}

声明而未使用的变量

fn main() {
  // let mut singer = "aimyon";
  // cargo run/build 会提示singer变量声明未使用
  // 所以rust支持给变量加 _ 忽略
  let mut _singer = "aimyon";
}

变量与常量(使用const声明)

  • 常量:常量在绑定值以后也是不可变的,但是他与不可变的变量有很多区别:
    • 不可以使用mut关键字,常量永远不可变 🙅
    • 声明常量使用const关键字,同时必须标注类型
    • 常量可以在任何作用域内进行声明,包括全局作用域
    • 常量只可以绑定到常量表达式,无法绑定到函数的调用结果或只能在运行时才能计算出的值
  • 在程序运行期间,常量在其声明的作用域内一直有效
  • 命名规范:所有字母大写,每个单词使用下划线_分割

shadowing(Rust 语言圣经中翻译为:变量遮蔽,个人喜欢这种翻译)

  • 可以使用相同的变量名声明新的变量,新的变量就会 shadow(遮蔽)之前的同名变量

    fn main() {
    // let x = 10969;
    // let x = 3636;
    // // 如果这样写 虽然后一个x已经遮蔽第一个x,但是rust会提示第一个x为使用
    // println!("This number is {}", x);
    
    let x = 10969;
    let x = x + 3636;
    
    printli!("This number is {}", x);
    }
    
    • 在后续的代码中这个变量名代表的就是新的变量
  • ⚠️ 但是 ⚠️shadow和使用mut关键字的变量重新赋值不同:

    • 给未使用mut关键字用let声明的变量重新赋值,会导致编译错误
    • 而使用let声明的同名新变量(shadow 后的新变量)也是不可变的
    • 使用let声明的同名新变量的类型可以和之前的不一样
    fn main() {
      let vari = "vari"; // vari: &str
      let vari = vari.len();  // vari: usize,因为len()返回一个整数
    
      println!("variable {}", vari)
    }
    

数据类型:

  • 标量和复合类型

  • Rust 是静态编译语言,在编译时必须知道所有变量的类型

    • 基于使用的值,编译器通常能够推断出它的具体类型
    • 但如果可能的类型比较多(例如入门(一)中猜数游戏使用的将 String 转为整数的 parse 方法),必须添加类型的标注,否则编译会报错
    fn main() {
      {/* 因为parse返回类型Reasult 有error 所以必须使用expect对error情况处理 */}
      {/* 因为42能用很多类型u32 i32等表示,所以如果不标注类型会报错 */}
      let guess:u32 = '42'.parse().expect("It's not a number");
      {/* type annotations needed */}
      {/* let guess = '42'.parse().expect("It's not a number"); */}
    
      println!("This number is {}", guess);
    }
    

标量

  • 一个标量代表一个单个的值

  • Rust中有四个主要的标量类型:

    • 整数类型

      • 整数类型没有小数部分

      • 例如上面例子中的 u32 就代表一个无符号的整数类型,占据 32 位空间

      • 无符号整数类型以 u 开头,有符号以 i 开头

      • rust 整数类型分类,如下图

        rust整数类型分类
      • isizeusize 由计算机的具体架构决定,比如 windows 目前基本都是 x64 位系统,所以自然就是能用表示 64 位字节表示数字

        • 主要使用场景:对某种集合进行索引操作
      • 整数字面值:

        • 除了 byte 类型外,所有的数字字面值都允许使用类型后缀,如:57u8
        • 如果不清楚使用哪种类型,可以直接使用 Rust 默认类型
        • 整数的默认类型就是 i32:即使在 64 位系统下,速度也是很快的
      • 整数溢出:

    • 浮点类型

      • f32 单精度浮点类型
      • f64 双精度浮点类型(默认类型,因为和 f32 速度差不多,精度更高)
      • Rust 的浮点类型使用 IEEE-754 标准
    • 字符类型

    • 布尔类型

      • true
      • false
      • 一个字节大小

复合类型

  • 复合类型可以将多个值放在一个类型里

  • Rust 提供了两种基础的复合类型:TupleArray

    • Tuple

      • Tuple定义:

        • Tuple可以将多个类型的多个值放在一个类型里
        • Tuple里每个元素的类型可以不一样
        • Tuple长度是固定的,一旦声明无法改变
      • Tuple创建:

      • 小括号中,将值用逗号分开

      • Tuple中的每个位置都对应一个类型,Tuple中各元素的类型不必相同

      Tuple.rs
      fn main() {
        let tup: (i32, f64, u8) = (3636, 3.14, 69);
      
        {/* 解构赋值 */}
        let (x, y, z) = tup
      
        println!("{}, {}, {}", x, y, z);
        {/* 访问tuple元素的方法 */}
        println!("{}, {}, {}", tup.0, tup.1, tup.2);
      }
      
    • Array

      • Array定义:

        • Array也可以将多个值放在一个类型里
        • Array每个元素的类型必须是一样的
        • Array的长度也是固定的
      • Array创建:

        • 中括号中,用逗号隔开(和 JS 一样)
        Array.rs
        fn main() {
          let arr:[i32; 4] = [1, 2, 3, 4];
        
          println!("{}", arr);
        }
        
        • 另一种声明数组的方法:
          • 如果数组的每个元素值都相同,那么可以:
            1. 在中括号里指定初始值
            2. 然后是一个;
            3. 最后是数组的长度
          • 例如:let arr = [36; 5];就相当于let arr = [36, 36, 36, 36, 36]
      • 用处:

        • 当你想要把你的数据存放在 stack 上而不是 heap 上,或者想保证有固定数量的元素,这时推荐使用数组
        • 数组没有 Vector(和数组类似,但由标准库提供,但是 Vector 可以改变长度) 灵活
      • Array的类型:[类型; 长度]

      • Array的访问:

        • Array是 Stack 上分配的单个块的内存
        • 可以使用索引来访问数组的元素
        • 如果访问的索引超出了数组的范围:
          • 编译会通过
          • 运行会报错(panic):Rust不允许其继续访问相应地址的内存