趣味学Rust基础篇(数据类型)

作为一个名长期从事编码工作的码农,我一直觉得编写程序就想玩乐高一样,想象一下,你要用乐高积木搭建一个复杂的模型。每一块积木都有不同的形状和功能:有小小的 1x1 方块(基础积木),也有能组合多个小块的复杂组件(组合积木)。在 Rust 世界里,数据类型就是这些"积木"。我们要学习的,就是认识这些积木(数据类型),并用它们构建出强大的程序。

Rust 是一个静态类型语言,这就意味着它像一个非常严格的建筑师,必须在"开工"(编译)之前就搞清楚每一块积木的型号。不过,Rust 很聪明,很多时候它能根据你放进去的"零件"(值)自动猜出积木型号。

积木的两大类:标量(单一积木)和复合(组合积木)

Rust 的积木主要分两大类:

  1. 标量类型 (Scalar):代表一个独立的值,就像一个 1x1 的小方块。
  2. ** 复合类型 **(Compound):能把多个值组合在一起,就像一个能连接多个小方块的大组件。

第一类:标量积木(单一值)

标量积木有四种基本款:整数、浮点数、布尔值、字符

1. 整数积木(i32, u8, isize...)

整数就是没有小数点的数字,比如 42, -100

  • 有符号 vs 无符号

    • i 开头的(如 i32):有符号 (signed),能存正数、负数和零。i 代表 "integer"。
    • u 开头的(如 u8):无符号 (unsigned),只能存零和正数。u 代表 "unsigned"。
  • 位数 :后面的数字(如 32)代表这块积木的大小(位数),决定了它能存多大的数字。

    • i8:8位,范围是 -128 到 127。
    • u8:8位,范围是 0 到 255。
    • i32:32位,范围巨大,从 -2,147,483,648 到 2,147,483,647。

举例说明

rust 复制代码
let age: u8 = 25; // 年龄不可能是负数,用 u8 足够了
let temperature: i32 = -10; // 温度可以是零下,用 i32
let default_int = 42; // 不写类型,Rust 默认是 i32
  • isizeusize :这两个比较特殊,它们的大小取决于你的电脑是 32 位还是 64 位。它们通常用于数组索引内存地址

整数溢出 :我们可以想象一个 u8 盒子(最大装 255),你非要塞进去 256。

  • Debug 模式 (开发时):Rust 会立刻大喊"Panic!"(崩溃),提醒你出错了。
  • Release 模式(发布时):为了性能,Rust 会默默让它"回绕":256 变成 0,257 变成 1... 这通常不是你想要的!

安全处理溢出:Rust 提供了专门的"安全工具":

rust 复制代码
let max_u8: u8 = 255;
let result = max_u8.checked_add(1); // 检查加法是否会溢出
match result {
    Some(value) => println!("结果是 {value}"),
    None => println!("加法溢出啦!"),
}
  • 整数写法 :Rust 支持多种写法,还允许用 _ 当"千分位"分隔符,超贴心!

    rust 复制代码
    let decimal = 98_222;     // 十进制,就是 98222
    let hex = 0xff;           // 十六进制,255
    let octal = 0o77;         // 八进制,63
    let binary = 0b1111_0000; // 二进制,240
    let byte = b'A';          // 字节 (u8),65 (ASCII 'A')
2. 浮点数积木(f32, f64

浮点数就是带小数点的数字,比如 3.14, -0.001

  • f32:32位,单精度。
  • f64:64位,双精度。默认类型是 f64 ,因为现代 CPU 上它和 f32 差不多快,但精度更高。

例子

rust 复制代码
let pi = 3.1415926; // 不写类型,Rust 默认是 f64
let small_number: f32 = 1e-3; // 科学计数法,0.001

数学运算

rust 复制代码
fn main() {
    let sum = 5 + 10;        // 加法: 15
    let diff = 95.5 - 4.3;   // 减法: 91.2
    let prod = 4 * 30;       // 乘法: 120
    let quot = 56.7 / 32.2;  // 除法: 约 1.76
    let trunc = -5 / 3;      // 整数除法向零截断: -1 (不是 -1.666...)
    let rem = 43 % 5;        // 求余: 3
    println!("trunc = {trunc}, rem = {rem}");
}
3. 布尔积木(bool

最简单的积木,只有两个状态:true(真)和 false(假)。大小是 1 个字节。

例子

rust 复制代码
let is_raining = true;
let is_sunny: bool = false; // 显式类型注解
let comparison = 10 > 5;    // 比较表达式返回 bool: true

布尔值主要用于 if 条件判断。

4. 字符积木(char

char 是 Rust 中最基础的"字母"类型。注意 :它和字符串 String 不一样!

  • 单引号 ' ' 包裹。
  • 大小是 4 个字节,可以表示Unicode 标量值,所以不仅能表示英文、数字,还能表示中文、日文、表情符号(emoji)等!

例子

rust 复制代码
let letter = 'z';
let number = '7';
let heart = '❤';
let cat = '😻';
let chinese = '中';
let math_symbol = 'ℤ'; // 整数集符号

重要提示 :一个 char 不一定对应人类认知的一个"字符"。例如,一个带重音符号的字母 é 可能由多个 Unicode 码位组成。对于文本,通常使用 String 类型。


第二类:复合积木(组合值)

复合类型能把多个标量积木组合成一个更复杂的组件。

1. 元组积木(tuple

元组就像一个异构的、固定大小的盒子,可以装不同类型的东西。

  • 用小括号 ( ) 创建。
  • 一旦创建,大小不能改变。
  • 里面的元素可以是不同类型。

例子

rust 复制代码
// 创建一个元组,包含整数、浮点数和字符
let tup: (i32, f64, char) = (500, 6.4, 'z'); // 可以加类型注解

// 创建元组(不加类型注解,Rust也能推断)
let tup = (500, 6.4, 'z');

// 方法一:解构(Destructuring) - 把大盒子拆成小盒子
let (x, y, z) = tup; // x=500, y=6.4, z='z'
println!("y 的值是:{y}");

// 方法二:通过索引访问 - 直接从大盒子里拿东西
let x = tup.0; // 第一个元素 (索引从0开始)
let y = tup.1; // 第二个元素
let z = tup.2; // 第三个元素
println!("x={x}, y={y}, z={z}");

特殊元组:单元类型 ()

  • 一个空的元组 (),读作 "unit"。

  • 它既是 也是类型

  • 当一个函数不返回任何有意义的值时,它会隐式返回 ()

    rust 复制代码
    fn do_something() {
        println!("我做了点事!");
        // 没有 return 语句,函数隐式返回 ()
    }
2. 数组积木(array

数组就像一个同质的、固定大小的盒子,所有格子必须装相同类型的东西。

  • 用方括号 [ ] 创建。
  • 所有元素类型必须相同。
  • 大小固定,创建后不能改变。
  • 数据通常分配在上,访问非常快。

例子

rust 复制代码
// 创建数组
let a = [1, 2, 3, 4, 5]; // 类型是 [i32; 5]

// 显式类型注解
let a: [i32; 5] = [1, 2, 3, 4, 5];

// 用同一个值初始化所有元素
let a = [3; 5]; // 等同于 [3, 3, 3, 3, 3]

// 访问数组元素(通过索引)
let first = a[0]; // 第一个元素
let second = a[1]; // 第二个元素
println!("第一个元素是:{first}");

**数组 vs 向量 **(Vec)

  • 数组 :大小固定,栈上分配,性能极高。适合大小已知且不变的场景,比如一周的天数、一年的月份。

    rust 复制代码
    let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
                  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; // 12个月,固定!
  • **向量 **(Vec):大小可变,堆上分配。当你不确定需要多少元素,或者元素会增减时,用 Vec。这是标准库提供的类型。

数组越界:Rust 的"安全护栏"

这是 Rust 内存安全的核心体现!尝试访问数组不存在的索引会怎样?

rust 复制代码
use std::io;

fn main() {
    let a = [1, 2, 3, 4, 5];
    println!("请输入一个索引 (0-4):");

    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("读取失败");

    let index: usize = input.trim().parse().expect("请输入数字");

    let element = a[index]; // ⚠️危险操作!如果 index >= 5 会怎样?
    println!("元素是:{element}");
}
  • 结果 :如果你输入 10,程序不会偷偷访问内存垃圾,而是会立刻 panic (崩溃),并清晰地告诉你:
    thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10'
  • 为什么这很重要?在 C/C++ 等语言中,这种越界访问可能导致程序读取或写入非法内存,造成安全漏洞(如缓冲区溢出攻击)。Rust 通过这种"快速失败"机制,在运行时保护你,确保内存访问是安全的。

总结:Rust 数据类型的"设计哲学"

通过学习这些数据类型,我们可以看到 Rust 的核心思想:

  1. 明确性与安全性:类型必须清晰(静态类型),默认不可变,访问越界会 panic。这些规则在编译时和运行时帮你抓住错误。
  2. 性能与控制 :提供了从 u8i128 的精细整数选择,isize/usize 用于系统编程,数组在栈上分配以获得极致性能。
  3. 现代性char 支持 Unicode,让程序天生支持多语言。
  4. 组合性 :通过元组和数组,可以轻松组合数据。而 Vec 等标准库类型则提供了更高级的抽象。
  5. 零成本抽象:这些类型和检查带来的安全性,几乎没有运行时性能损失。

现在,你已经掌握了 Rust 构建程序的"基本积木"。记住,选择正确的"积木"(数据类型)是写出高效、安全、可维护代码的第一步!

相关推荐
熙客6 分钟前
Java:LinkedList的使用
java·开发语言
CYRUS_STUDIO13 分钟前
Miniconda 全攻略:优雅管理你的 Python 环境
前端·后端·python
用户2986985301419 分钟前
如何使用 Spire.Doc 删除 Word 中的表格?
后端
blueblood22 分钟前
🗄️ JFinal 项目在 IntelliJ IDEA 中的 Modules 配置指南
java·后端
lovebugs37 分钟前
Kubernetes 实战:Java 应用配置与多环境管理
后端·面试·kubernetes
大飞pkz1 小时前
【Lua】题目小练12
开发语言·lua·题目小练
赵得C1 小时前
Java 多线程环境下的全局变量缓存实践指南
java·开发语言·后端·spring·缓存
nightunderblackcat2 小时前
新手向:Python编写简易翻译工具
开发语言·python
打不过快跑2 小时前
YOLO 入门实战(二):用自定义数据训练你的第一个检测模型
人工智能·后端·python