二、语言基础 (一)

142 阅读6分钟

二、语言基础 (一)

1. 输出到控制台

  • 两个输出宏:

    • print!("输出内容: {} {} {}", var1, var2, var3)

      • 与 Java System.out.print 的效果相同
    • println!("输出内容: {} {} {}", var1, var2, var3)

      • 与 Java System.out.println 的效果相同
  • 具体用法

    • 这两个输出宏的语法完全相同

    • 如果想输出自定义文字 + 变量,那么与 C, Java 类似

    • 示例代码

      fn main() {
          let a= "aa";
          let b = "bb";
          ​
          // 输出指定的变量
          println!("这是你想自定义的文字:{},{}", a, b); // 这是你想自定义的文字:aa,bb// 重复输出某个变量
          println!("重复两遍变量 a:{0},{0}", a, b); // 重复两遍变量 a:aa,aa
          println!("重复两遍变量 b:{1},{1}", a, b); // 重复两遍变量 b:bb,bb// 输出左花括号 '{' 或右花括号 '}'
          println!("输出花括号:{{"); // 输出花括号:{
          println!("输出花括号:}}"); // 输出花括号:}
          println!("输出花括号:{{}}"); // 输出花括号:{}// 输出其他转义字符时,和其他编程语言一样,都是使用反斜杠 ''
          println!("输出换行符:\n"); // 输出换行符:// 后续还会介绍到另外一种打印变量的快捷方式
          ​
      }
      

2. 变量定义

  • Rust 是一门强类型语言,但某些情况下可以省略类型注解

    • 一个变量的类型可以由类型注解 (参考 Typescript 的说法)确定
    • 一个变量的类型也可以由定义时赋值的值类型确定
  • 变量定义关键字:let, const, mut

    变量类型关键字类型注解可重新赋值Shadowing 特性示例
    不可变变量let非必须不可支持let a= 'a'
    可变变量let mut非必须支持let mut a = 'a'
    常量const必须不可不支持const C: i32 = 456
  • 重影 (Shadowing) 特性: 用同一个名字重新代表另一个变量实体,其类型、可变属性和值都可以变化

    • 这是 Rust 相比于其他语言中比较特殊的一个特性
  • 示例代码

    fn main() {
        let a = "abc"; // 定义了一个字符串类型的不可变变量 a
        let mut b = 123; // 定义了一个整数型的可变变量 b
        const C: u32 = 456; // 定义了一个无符号32位整型常量 c
    ​
        let a = "efg"; // 允许。a 是不可变变量,利用了 shadowing 特性
        let a = b; // 允许。a 是不可变变量,利用了 shadowing 特性
        b = c; // 允许。类型匹配,且 b 是可变变量
    ​
        // 下面是变量赋值的反例
        a = "xyz"; // 不允许。a 是不可变变量
        b = "123"; // 不允许。类型不匹配
        c = 789; // 不允许。c 是常量
    ​
        // 上一个 a 的作用域到这里就结束了,下面是新 a 的作用域
        let mut a = c; // 现在,a 变量的类型变成了无符号32位整型
        a = 789; // 允许,类型匹配
        a = "abc"; // 不允许,类型不匹配
    }
    

3. 数据类型

3.1 标量类型

  • 标量类型:代表一个单独的值

    • 类似于 JavaScript 里的字面量
  • Rust 中有四种标量类型:整型、浮点型、布尔类型和字符类型

3.1.1 整型

位长度有符号无符号
8位i8u8
16位i16u16
32位i32u32
64位i64u64
128位i128u128
archisizeusize
  • isize 和 usize 是用来衡量数据大小的,它们的位长度取决于所运行的目标平台,主要作为某些集合的索引

  • 表述方式

    • 十进制:和 C, Java, JavaScript 等编程语言相同
    • 十六进制:和 C, Java, JavaScript 等编程语言相同
    • 八进制:和 C, Java, JavaScript 等编程语言相同
    • 二进制:和 C, Java, JavaScript 等编程语言相同
    • 字节 (特有):只能表示无符号8位的整型数字 (即 u8):b'A'
  • 不写类型注解时,整型的类型默认是 i32 ,因为它通常是最快的,甚至在 64 位系统上也是

  • 整型溢出

    • 比如:一个 u8 的变量,它允许的最大值是 255,如果把它加一

      • 在 debug 模式编译运行时,会直接 panic

      • 在 release 模式编译运行时,会进行二进制补码包装

        • 二进制补码包装:255+1 会变成 0,255+2 会变成 1,依次类推

3.1.2 浮点型

  • 32位:f32
  • 64位:f64
  • 不写类型注解时,浮点数的类型默认是 f64,因为在现代 CPU 中,它与 f32 速度几乎一样,不过精度更高

3.1.3 布尔型

  • 类型注解为 bool
  • 只有 truefalse 两个值
  • 主要的使用场景是条件表达式

3.1.4 字符类型

  • 类型注解为 char

  • 必须包裹在单引号 '' 中,且其中只能有一个合法字符 (不含转义符)

    • 和 C 语言的字符类型很像
  • 大小为四个字节(four bytes),代表了一个 Unicode 标量值(Unicode Scalar Value)

3.2 复合类型

  • 复合类型:可以由多个值组合而来的类型
  • Rust 中有两种复合类型:元组,数组

3.2.1 元组

  • 用一对小括号 () 包裹

    • (value1, value2, ...)
  • 元组里的每一个元素可以是不同类型的

  • 元组里的元素可以通过 varName.index 来调用

    fn main() {
        let tup: (i32, f64, u8) = (500, 6.4, 1);
        println!("{}, {}, {}", tip.0);
        let (x, y, z) = tup; // 类似 JavaScript 里的解构赋值
    }
    ​
    
  • 类似 Python 里的元组,也类似 Typescript 的元组 (但表现不一样)

3.2.2 数组

  • 用一对中括号包裹一组 数据类型相同 的元素

    • 和 Java 里的数组概念基本相同
  • 仅当数组用 let mut 关键字定义时,数组的元素值、数组本身才可变

4. 运算符号

  • 和其他编程语言相同的运算符

    符号名称备注
    =赋值运算符
    +, -, *, /, %, <<, >>基本数值运算符这些符号均可与赋值运算符组成组合运算符
    `&,, !, ^`位运算符只有 & 和 `` 可以和赋值运算符组成组合运算符
    `&&,, !`逻辑运算符
    <, <=, >, >=, ==, !=条件运算符
    ,元素分隔符
    .成员访问符
  • 相对特殊的运算符

    符号名称备注
    !宏展开运算符
    &借用运算符可以借用类型或变量, 与 C 语言的取地址操作符概念相似
    *解引操作符与 C 语言的指向运算符概念相似
    ->返回值类型指定符用于为函数/方法指定返回值类型
    ..范围运算符在数字范围、数组、元组中用得比较多
  • 相比于其他编程语言,Rust 中没有的运算符

    • 递增一/递减一 运算符 ++/--

    • 无符号右移 运算符 >>>

    • 三元运算符 exp ? exp2 : exp3

      • 可以通过 let b = if a== exp { exp2 } else { exp3 }; 来实现相同的效果,但是此时的 exp2 必须和 exp3 是相同类型的才行

5. 注释

  • 普通注释

    • 单行注释:// 这是注释内容
    • 任意行注释:/* 这里的内容可以跨越任意行 */
  • 文档注释

    • 方式一:/// 这是文档注释

      • 这样的文档注释,可通过 cargo doc 命令将项目中的说明注释转换成 HTML 格式的说明文档
    • 方式二:/** 这是文档注释 */

      • 这种文档注释没有试过
  • 示例代码

    fn main() {
        // 打印一个 bar
        bar();
        /*
          除了在上面打印一个 bar 之外
          还会在随后打印一个 foo
        */
        foo();
    }
    
    
    /**
     bar
     打印一个 bar
    */
    fn bar() {
        println!("bar");
    }
    
    
    /// foo
    /// 打印一个 foo
    fn foo() {
        println!("foo");
    }