跳转至

Variables

声明

Rust中用于声明变量的关键字是let,它的语法如下:

let [mut] <variable>[: <type>] [= <value>];

其中,类型和初始化的值都可以省略。如果一个变量从声明开始没有被赋值,就不能使用这个变量。如果没有指定类型但指定了初始化值,系统则会自动推断变量的类型。Rust还可以用{}来用一系列语句来初始化变量,也可以用()来一次性声明多个变量。没有用mut声明的变量是不可变的,不能被修改。

Rust中用于声明常量的关键字是const,用于声明静态变量的关键字是static。语法与let相似,但需要同时指定类型和初始化值。通常conststatic语句都是在全局作用域(即函数外)中声明的。

let可以用来重新声明一个变量,隐藏之前的变量,也可以用mut来改变一个变量的可变性。

Download source code

1
2
3
4
5
6
7
8
9
fn main() {
    let x: f64 = -20.48; // float
    let x: i64 = x.floor() as i64; // int
    println!("{}", x); // -21

    let s: &str = "hello"; // &str
    let s: String = s.to_uppercase(); // String
    println!("{}", s) // HELLO
}

变量类型

Rust的变量类型有

  • 一般类型
    • 布尔:bool,取值为truefalse,占用1个字节。
    • 字符:char,使用单引号,占用4个字节。
    • 整数:i8i128isize,取值范围为\([-2^{n-1}, 2^{n-1} - 1]\),可以用min_value()max_value()函数来获取类型的取值范围。isize的取值范围和系统指针长度相同。默认的整数类型是i32
    • 无符号整数:u8u128usize,取值范围为\([0, 2^n - 1]\)
    • 浮点数:f32f64,分别为单精度和双精度浮点数。默认的浮点数类型是f64
    • 字符串字面量:str,使用双引号,是不可变类型。字符串字面量(变量)的类型为&str,是引用类型。
    • 字符串:String,是可变类型,但不支持索引。字符串的引用或切片类型为&str
    • 单元类型:(),只有一个值(),没有return语句的函数的返回值类型为(),不占用内存。
  • 容器及相关类型
    • 使用println!打印容器时,需要用{:?}{:#?},前者为一行输出,后者在每个元素后面添加换行符。
    • 定长数组:[T; N],其中T为数组元素类型或重复的数组,N为数组长度,必须是常量。只有用mut声明的数组才能修改其中元素。
      • 注意不支持Copy trait的类型不能用[T; N]语法,必须逐个赋值。
      • 不同长度的数组是不同的类型,不能相互赋值。
    • 定长元组:(T1, T2, ..., Tn),其中T1Tn为元组中元素的类型。只有用mut声明的元组才能修改其中元素(类型必须匹配)。类似于Python,在变量声明阶段或赋值阶段,仅包含(可以被赋值的)变量元组可以作为赋值运算的左端项,此时会分别为每个变量分配对应的值,省略的变量用_表示。元组支持嵌套。单元素元组的语法为(<value>,)
    • 数组切片:&<parent>[<start>..<end>],注意切片是对<parent>的引用,是引用类型。元组不支持切片,只能用.0.1等来访问元素,类型为[T]
  • 迭代器,通常由容器对象的iter()方法生成。
  • 函数:需要用fn(arg1: type1, ...) -> return_type表示,函数以引用的方式传递。

整数类型

Rust中的整数字面量有如下写法:

  • 十进制:123_456
  • 十六进制:0x1230x开头,数字为0-9a-f
  • 八进制:0o1230o开头,数字为0-7
  • 二进制:0b1010b开头,数字为01
  • 字节:b'A'
  • 下划线_类似于千位分隔符,存在与否不影响数字的值

整数溢出

在Debug模式下,Rust会检查整数溢出,如果发生溢出,程序会panic。在Release模式下,Rust不会检查整数溢出,溢出后会按照二进制补码进行循环。

整数类型有如下方法:

  • 下文中的*addsubmuldiv等运算
  • wrapping_*:如果运算溢出,则取溢出后的值。
  • checked_*:如果运算溢出,则返回None
  • saturating_*:如果运算溢出,则返回目标类型的最大值或最小值。
  • overflowing_*:返回运算结果和是否溢出的标记

    let a: i32 = 1;
    let b: i32 = 2;
    let (c, overflow) = a.overflowing_add(b);
    println!("{} {}", c, overflow); // 3 false
    

浮点数类型

  1. 浮点数没有实现Eq trait,因此不能直接用==!=来比较,也不能作为字典的键。
  2. 数学上无定义的运算,如0.0 / 0.0,Rust会返回NaN(Not a Number)。与NaN的运算结果总是NaN,并且NaN不能参与比较运算。
  3. 由于NaN的存在,浮点数没有实现Ord trait,因此不能直接用于sort()等需要Ord trait的方法,需要用partial_cmp().unwrap()来进行比较。
  4. 由于浮点数的精度问题,浮点数的比较应该用abs()<>来进行。

浮点数类型有如下方法:

  • is_nan():判断是否为NaN

字符串字面量类型

字符串字面量类型有如下方法:

  • len():返回字符串长度。

    let s = "hello";
    println!("{}", s.len()); // 5
    
  • lines():按换行符\n分割字符串,返回迭代器。

    let s = "hello\nworld";
    for line in s.lines() {
        println!("{}", line);
    }
    
  • split():按给定字符分割字符串,返回迭代器。

    let s = "hello world";
    for word in s.split(" ") {
        println!("{}", word);
    }
    
  • trim():去除字符串首尾的空白字符。

    let s = " hello world ";
    println!("{}", s.trim()); // "hello world"
    
  • parse():将字符串转换为其他类型,如parse::<i32>()将字符串转换为i32类型。当转为数字时,数字不能超过类型的取值范围,否则会报错。

    let s = "123";
    let n: i32 = s.parse().unwrap(); // 返回值是`Result`类型
    

    自定义类型如果需要通过parse()转换为字符串,需要实现std::str::FromStr trait,参见Impl & Trait

  • to_string():将字符串字面量转换为String类型。

  • chars():返回字符串的字符迭代器。
  • bytes():返回字符串的字节迭代器。

字符串类型

字符串类型有如下方法:

  • push()push_str():分别用于在字符串末尾添加字符和字符串字面量。
  • insert()insert_str():分别用于在字符串中的指定位置插入字符和字符串字面量。
  • replace(A, B)replacen(A, B, n):分别用于将字符串中的A替换为Breplacen还可以指定替换次数n,返回替换后的新字符串。
  • replace_range(range, A):用于将原字符串的指定范围替换为新的字符串A,返回替换后的原字符串。
  • pop():删除并返回字符串末尾的字符,如果字符串为空则返回None
  • remove():删除并返回字符串中指定位置的字符。给定的索引必须是有效的字符边界。
  • truncate():删除从指定位置开始到字符串结尾的全部字符。
  • clear():清空字符串。
  • +运算符:用于连接两个字符串,右端项为&str类型。

数组类型

数组越界

Rust会检查数组访问越界问题。

数组类型有如下方法:

  • std::array::from_fn():根据函数返回值生成数组。

    let a: [String; 8] = std::array::from_fn(|_i| String::from("This is Rust"));
    

迭代器类型

迭代器类型有如下方法:

  • map(fn):对迭代器中的每个元素应用函数fn,返回新的迭代器。

    let v = vec![1, 2, 3];
    for i in v.iter().map(|x| x * 2) {
        print!("{}", i); // 246
    }
    
  • collect():将迭代器转换为容器(定长数组)。

    let v = vec![1, 2, 3];
    let v2: Vec<i32> = v.iter().map(|x| x * 2).collect();
    

运算符

Rust的运算符与C/C++类似

  • 四则运算符:+ - * / %
  • 比较运算符:== != > < >= <=
  • 逻辑运算符:&& || !
  • 位运算符:& | ^ << >> !!为按位取反)
  • 原位赋值运算符:+= -= *= /= %= &= |= ^= <<= >>=
  • 类型转换运算符:as,如let b = (a as f64) / 2.0;
  • 引用与解引用运算符:& &mut *,其中&用于获取变量的引用(borrow),&mut用于获取变量的可变引用,*用于解引用。

评论