Rust 数据类型

发布于:2025-06-06 ⋅ 阅读:(17) ⋅ 点赞:(0)

Rust 数据类型

在这里插入图片描述

在 Rust 中,每个值都有特定的数据类型,数据类型告诉 Rust 该如何处理这些数据。我们将介绍两类数据类型:标量类型和复合类型。

请注意,Rust 是静态类型语言,这意味着编译时必须知道所有变量的类型。编译器通常可以根据值和用法推断类型。但在某些情况下(比如将 String 转换为数字类型时),需要添加类型注解,例如:

let guess: u32 = "42".parse().expect("Not a number!");

如果没有 : u32 类型注解,Rust 会报如下错误,提示需要更多类型信息:

$ cargo build
    Compiling no_type_annotations v0.1.0 (file:///projects/no_type_annotations)
error[E0284]: type annotations needed
 --> src/main.rs:2:9
  |
2 |     let guess = "42".parse().expect("Not a number!");
  |         ^^^^^        ----- type must be known at this point
  |
  = note: cannot satisfy `<_ as FromStr>::Err == _`
help: consider giving `guess` an explicit type
  |
2 |     let guess: /* Type */ = "42".parse().expect("Not a number!");
  |              ++++++++++++

更多信息可通过 rustc --explain E0284 查看。其他数据类型也有类似的类型注解。

标量类型

标量类型表示单一值。Rust 有四种主要的标量类型:整数、浮点数、布尔值和字符。你可能在其他语言中也见过这些类型。

整数类型

整数是不带小数部分的数字。我们在第 2 章用过 u32 类型,表示 32 位无符号整数(有符号类型以 i 开头)。下表展示了 Rust 内置的整数类型:

长度 有符号 无符号
8 位 i8 u8
16 位 i16 u16
32 位 i32 u32
64 位 i64 u64
128 位 i128 u128
架构相关 isize usize

有符号类型可表示负数,无符号类型只能表示正数。Rust 使用二进制补码存储有符号数。

每种有符号类型能存储的范围是 −(2ⁿ⁻¹) 到 2ⁿ⁻¹−1,无符号类型是 0 到 2ⁿ−1。例如,i8 范围是 −128 到 127,u8 范围是 0 到 255。

isizeusize 的大小取决于计算机架构(32 位或 64 位)。

整数字面量可以用多种形式表示:

字面量类型 示例
十进制 98_222
十六进制 0xff
八进制 0o77
二进制 0b1111_0000
字节(u8) b’A’

如果不确定用哪种类型,Rust 默认使用 i32isizeusize 主要用于集合索引。

整数溢出

例如,u8 的范围是 0 到 255。如果赋值超出范围(如 256),在 debug 模式下会 panic;release 模式下会发生环绕(256 变为 0,257 变为 1)。依赖溢出行为是错误的。

Rust 提供了多种方法处理溢出:

  • wrapping_* 方法:始终环绕
  • checked_* 方法:溢出时返回 None
  • overflowing_* 方法:返回值和是否溢出的布尔值
  • saturating_* 方法:溢出时取最大或最小值

浮点类型

Rust 有两种浮点类型:f32f64,分别为 32 位和 64 位,默认是 f64。所有浮点类型都是有符号的,遵循 IEEE-754 标准。

示例:

fn main() {
     let x = 2.0; // f64
     let y: f32 = 3.0; // f32
}

数值运算

Rust 支持加、减、乘、除、取余等基本运算。整数除法向零取整。

fn main() {
     let sum = 5 + 10;
     let difference = 95.5 - 4.3;
     let product = 4 * 30;
     let quotient = 56.7 / 32.2;
     let truncated = -5 / 3; // 结果为 -1
     let remainder = 43 % 5;
}

布尔类型

Rust 的布尔类型为 bool,只有 truefalse 两个值,占 1 字节。

fn main() {
     let t = true;
     let f: bool = false; // 显式类型注解
}

布尔值主要用于条件表达式(如 if)。

字符类型

Rust 的 char 类型用于表示单个字符,4 字节,支持 Unicode 标量值。

fn main() {
     let c = 'z';
     let z: char = 'ℤ';
     let heart_eyed_cat = '😻';
}

字符字面量用单引号。char 能表示多种字符,包括表情、汉字等。

复合类型

复合类型可以将多个值组合成一个类型。Rust 有两种原生复合类型:元组和数组。

元组类型

元组可以将不同类型的多个值组合在一起,长度固定。

fn main() {
     let tup: (i32, f64, u8) = (500, 6.4, 1);
}

可以使用模式匹配解构元组:

fn main() {
     let tup = (500, 6.4, 1);
     let (x, y, z) = tup;
     println!("The value of y is: {y}");
}

也可以通过索引访问元组元素:

fn main() {
     let x: (i32, f64, u8) = (500, 6.4, 1);
     let five_hundred = x.0;
     let six_point_four = x.1;
     let one = x.2;
}

空元组 () 被称为单元类型,表示空值或空返回类型。

数组类型

数组用于存储相同类型、固定长度的多个值。

fn main() {
     let a = [1, 2, 3, 4, 5];
}

数组适合需要固定数量元素且数据分配在栈上的场景。更灵活的可变长度集合请使用 vector。

数组类型写法:

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

也可以用相同值初始化:

let a = [3; 5]; // 等价于 [3, 3, 3, 3, 3]
访问数组元素

通过索引访问数组元素:

fn main() {
     let a = [1, 2, 3, 4, 5];
     let first = a[0];
     let second = a[1];
}
非法访问数组元素

如果访问越界(如索引为 10),程序会 panic:

use std::io;

fn main() {
     let a = [1, 2, 3, 4, 5];
     println!("Please enter an array index.");
     let mut index = String::new();
     io::stdin()
          .read_line(&mut index)
          .expect("Failed to read line");
     let index: usize = index
          .trim()
          .parse()
          .expect("Index entered was not a number");
     let element = a[index];
     println!("The value of the element at index {index} is: {element}");
}

如果输入超出范围,程序会报错并退出:

thread 'main' panicked at src/main.rs:19:19:
index out of bounds: the len is 5 but the index is 10

Rust 在运行时检查索引是否合法,防止非法内存访问。这体现了 Rust 的内存安全原则。

代码示例如下:

fn main() {
    // 整数
    let a = 10; // i32
    let b: i64 = 20; // i64
    // 打印整数
    println!("Integer a: {}, b: {}", a, b);
    // 浮点数
    let x = 2.0; // f64
    let y: f32 = 3.0; // f32
    // 打印浮点数
    println!("Float x: {}, y: {}", x, y);
    // 数值类型转换
    let int_to_float = a as f64; // i32 转 f64
    let float_to_int = y as i32; // f32 转 i32
    // 打印转换结果
    println!("Converted int to float: {}, Converted float to int: {}", int_to_float, float_to_int);
    // 数值运算
    let sum = 5 + 10;
    let difference = 95.5 - 4.3;
    let product = 4 * 30;
    let quotient = 56.7 / 32.2;
    let truncated = -5 / 3; // 结果为 -1
    let remainder = 43 % 5;
    // 打印数值运算结果
    println!("Sum: {}, Difference: {}, Product: {}, Quotient: {}, Truncated: {}, Remainder: {}", 
             sum, difference, product, quotient, truncated, remainder);
    // 布尔值
    let is_active = true; // bool
    let is_valid: bool = false; // bool
    // 字符
    let c = 'A'; // char
    let d: char = 'Z'; // char    
    let z: char = 'ℤ';
    let heart_eyed_cat = '😻';
    // 打印字符
    println!("Character c: {}, d: {}, z: {}, heart_eyed_cat: {}", c, d, z, heart_eyed_cat);
    // 字符串
    let s = "Hello, world!"; // &str
    let t: String = String::from("Hello, Rust!"); // String
    // 元组
    let tuple = (1, 2.5, 'c'); // (i32, f64, char)
    let (x1, y1, z1) = tuple; // 解构元组
    // 数组
    let arr = [1, 2, 3, 4, 5]; // [i32; 5]
    let arr2: [f64; 3] = [1.0, 2.0, 3.0]; // [f64; 3]
    // 切片
    let slice = &arr[1..4]; // &[i32]
    let slice2: &[f64] = &arr2[0..2]; // &[f64]
    // 枚举
    enum Direction {
        Up,
        Down,
        Left,
        Right,
    }
    let dir = Direction::Up; // 使用枚举
    // 结构体
    struct Point {
        x: f64,
        y: f64,
    }
    let p = Point { x: 1.0, y: 2.0 }; // 创建结构体实例
    // 使用结构体
    println!("Point coordinates: ({}, {})", p.x, p.y);
    // 使用枚举
    match dir {
        Direction::Up => println!("Moving up"),
        Direction::Down => println!("Moving down"),
        Direction::Left => println!("Moving left"),
        Direction::Right => println!("Moving right"),
    }
    // 打印基本数据类型
    println!("Integer a: {}, b: {}", a, b);
    println!("Float x: {}, y: {}", x, y);
    println!("Boolean is_active: {}, is_valid: {}", is_active, is_valid);
    println!("Character c: {}, d: {}", c, d);
    println!("String s: {}, t: {}", s, t);
    println!("Tuple values: ({}, {}, {})", x1, y1, z1);
    println!("Array values: {:?}", arr);
    println!("Array2 values: {:?}", arr2);
    println!("Slice values: {:?}", slice);
    println!("Slice2 values: {:?}", slice2);
    // 结束程序
    println!("Program finished successfully.");
}

运行结果如下:

Integer a: 10, b: 20
Float x: 2, y: 3
Converted int to float: 10, Converted float to int: 3
Sum: 15, Difference: 91.2, Product: 120, Quotient: 1.7608695652173911, Truncated: -1, Remainder: 3
Character c: A, d: Z, z: ℤ, heart_eyed_cat: 😻
Point coordinates: (1, 2)
Moving up
Integer a: 10, b: 20
Float x: 2, y: 3
Boolean is_active: true, is_valid: false
Character c: A, d: Z
String s: Hello, world!, t: Hello, Rust!
Tuple values: (1, 2.5, c)
Array values: [1, 2, 3, 4, 5]
Array2 values: [1.0, 2.0, 3.0]
Slice values: [2, 3, 4]
Slice2 values: [1.0, 2.0]
Program finished successfully.

网站公告

今日签到

点亮在社区的每一天
去签到