Skip to content

数据类型

标量类型

分类 类型
整数类型 i8, i16, i32, i64, i128, isize, u8, 816, u32, u64, u128, usize
浮点类型 f32, f64
布尔类型 bool (true, false)
字符类型 char

整数类型

Length Signed Unsigned
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
128-bit i128 u128
arch isize usize

整数字面值

Number literals Example
Decimal 98_200
Hex 0xff
Octal 0o75
Binary 0b1111_0011
Byte(u8 only) b'A'

除了 byte 类型外,所有整数字面值都可以使用类型后缀:

let x = 9122i16
let y = 0xffi64
let b = 0b1100_1011u8

Tip

Rust 默认整数类型为 i32

整数溢出

整数溢出指:值超过了类型的最大范围。

例如:u8的范围是 0~255,如果你把一个 u8 类型变量设为 256,那么:

  • 调试模式下:Rust 会检查整数溢出,在发生溢出时 panic
  • 发布模式下:Rust 不会检查整数溢出,在发生溢出时进行「环绕」操作:
    • 256 变成 0, 257 变成 1...
    • 不过程序不会 panic

浮点类型

Rust 浮点类型使用 IEEE-754 标准。

Rust 支持对浮点类型取余,但要求两边都是同类型浮点数才行,例如:

let x: f32 = 1.0
let y: f32 = 0.3
let z = x % y   // z 的值为 0.1

Tip

Rust 默认整数类型为 f64

复合类型

元组 Tuple

元组是一组 有序的、不可变的 元素的集合。

元组可以将多个类型的多个值放在一个类型里。

元组的长度是固定的,一旦声明就无法改变。

  • 元组的声明形式: (类型1, 类型2, ...);
  • 元组的赋值形式: (值1, 值2, ...);
  • 元组的访问形式: 元组名称.下标,使用 . 运算符。

Example

fn main() {
    let tup: (i32, f64, u8) = (100, 3.14, 5);
    println!("{}, {}, {}", tup.0, tup.1, tup.2);
}

元组可以被解构,例如:

let tup: (i32, f64, u8) = (100, 3.14, 5);
let (x, y, z) = tup;

数组

数组是一组 有序的,可变的 元素的集合。

数组中的值类型必须相同。

数组的长度是固定的,一旦声明就无法改变。

  • 数组的声明形式: [类型; 长度];
  • 数组的赋值形式: [值1, 值2, ...];
  • 数组的访问形式: 数组[下标],使用 [] 运算符。

Example

let a:[i64; 5] = [1, 2, 3, 4, 5];

当数组下标越界时,Rust 编译器可以检查出简单情况,但是复杂情况就检查不了。

一旦数组下标越界,运行时会报错。(runtime 会 panic)

简单情况,编译器能检查出来:

fn main() {
    let arr: [i32; 5] = [10, 11, 12, 13, 14];

    let index = 10;
    let elem = arr[index];  // 这种情况编译器是能检查出来的
}

复杂情况,编译器也无能为力:

fn main() {
    let arr: [i32; 5] = [10, 11, 12, 13, 14];

    let index = [5, 7, 8];
    let elem = arr[index[1]];   // 这种情况编译器检查不出来的,运行时会 panic
}

Range

Range 是 rust 的一种语法,使用 .. 操作符。

fn main() {
    for elem in (1..4).rev() {
        println!("{}", elem);
    }
    println!("Lift Off!");
}
expression type range
start..end std::ops::Range start <= x < end
start.. std::ops::RangeFrom start <= x <= end
     ..end std::ops::RangeTo     0 <= x < end
     .. std::ops::RangeRull     0 <= x <= end
start..=end std::ops::RangeInclusive start <= x <= end
     ..=end std::ops::RangeToInclusive     0 <= x <= end
let arr = [0, 1, 2, 3, 4];
assert_eq!(arr[ ..  ], [0, 1, 2, 3, 4]);
assert_eq!(arr[ .. 3], [0, 1, 2      ]);
assert_eq!(arr[ ..=3], [0, 1, 2, 3   ]);
assert_eq!(arr[1..  ], [   1, 2, 3, 4]);
assert_eq!(arr[1.. 3], [   1, 2      ]);
assert_eq!(arr[1..=3], [   1, 2, 3   ]);

Vec

向量是一组 有序的,可变的 元素的集合。

向量可以直接和数组比较

向量有以下4中创建方式:

  1. Vec::new(): 创建空的 vec
  2. Vec::with_capacity(): 创建空的 vec 并指定容量
  3. vec![], vec!(), vec!{}: 通过宏创建并初始化 vec
  4. vec![v;n], vec!(v;n), vec!{v,n}: 创建并初始化 vec,共n个元素,每个元素都初始化为 v
fn main() {
    let mut v1 = Vec:new();
    v1.push(1); // 追加时根据元素推导 v1 的数据类型为 Vec<i32>
    v1.push(2);
    v1.push(3);
    v1.push(4);
    assert_eq!(v1, [1, 2, 3, 4])    // vec 可以直接和数组比较

    let v2 = Vec::with_capacity(10);
    let v3 = vec![1, 2, 3, 4];

    let v3 = vec![3; 4];    // 等价于 vec![3, 3, 3, 3]
    let v3 = vec!(3; 4);    // 等价于 vec!(3, 3, 3, 3)
    let v3 = vec!{3; 4};    // 等价于 vec!{3, 3, 3, 3}
}

向量有多种访问元素的方式:

  1. v[下标]: 中括号运算符的方式。这种方式当下标越界时将==会== panic
  2. v.get(下标): get 方法,这种返回 vec 中指定下标元素的不可变引用,下标越界时==不会== panic,会返回 None
  3. v.get_mut(下标): get 方法,这种返回 vec 中指定下标元素的可变引用,下标越界时==不会== panic,会返回 None
  4. v.pop(): pop 方法,随机返回一个并移除元素
fn main() {
    let v = vec![1, 2, 3, 4];
    let n: usize = 3;

    // 使用中括号运算符访问,下标越界时会 panic
    println!("{}, {}", v[0], v[n]);
    // println!("{}", v[9]);

    // 使用 get 方法
    println!("{}", v.get(0));

    // 使用 get_mut 方法
    println!("{}", v.get_mut(0));
}

遍历 vec:

fn main() {
    let v = vec![1, 2, 3, 4];

    for i in &v { .. }      // 获得引用
    for i in &mut v { .. }  // 获得可变引用
    for i in v { .. }       // 获得所有权,此时v的所有权将会变动
}