Rust 数据类型详解

news2025/1/22 8:02:22

一、标量类型(Scalar Types)

标量类型代表一个单独的值。Rust 中有四大基本标量类型:整数(integer)、浮点数(floating-point number)、布尔(boolean)和字符(character)。这几种类型在大多数编程语言中都很常见。

1. 整数类型(Integer Types)

整数(integer)是没有小数部分的数字。在之前的猜数字游戏教程里,我们用到了 u32。这个类型声明表示该值是一个无符号(unsigned)32 位整数(如果是有符号类型,会以 i 开头,例如 i32)。

下表展示了 Rust 中所有内置的整数类型,每个类型要么是有符号(signed),要么是无符号(unsigned),并且有明确的位数大小。

长度有符号无符号
8-biti8u8
16-biti16u16
32-biti32u32
64-biti64u64
128-biti128u128
archisizeusize
  • 有符号(signed)表示数值可能为正也可能为负,所以存储时需要符号位;
  • 无符号(unsigned)则只表示非负数(0 或正数),不需要符号位。

对于有符号整数,如果类型是 i8,它可以存储从 -128 到 127 的数值;若是 i16,则范围会相应扩大,以此类推。无符号类型则从 0 起算。例如 u8 能表示 0 到 255。

isizeusize 根据系统架构的不同而变化:在 64 位架构上是 64 位,在 32 位架构上是 32 位。这些类型常用于根据系统架构进行索引或内存大小计算等场景。

1.1 整数字面量

在 Rust 中可以使用多种形式来表达整数字面量(literal),如下表所示:

数字字面量形式示例
十进制98_222
十六进制0xff
八进制0o77
二进制0b1111_0000
字节(仅限 u8b'A'

注意:

  • 可以在数字中使用下划线 _ 作为分隔符来提高可读性,例如 1_0001000 等价。
  • 如果需要指定类型,可以在数字后面加上类型后缀,比如 57u8

通常如果不确定该用什么整数类型,Rust 默认使用 i32。若需要根据系统架构进行索引等场景时,才考虑使用 isizeusize

1.2 整数溢出(Integer Overflow)

假设我们有一个 u8 类型的变量,它能表示的数值范围是 [0, 255]。如果尝试将其赋值为 256,就会发生整数溢出integer overflow),导致以下两种行为之一:

  1. 调试(debug)模式编译:Rust 会执行溢出检查,一旦发现溢出,就会在运行时 panic(程序崩溃并退出)。
  2. 发布(release)模式编译:Rust 不做溢出检查,而是进行二补码环绕two’s complement wrapping)。换言之,超出最大可表示值时会“环绕”回最小值。例如,对于 u8 类型,256 会变成 0,257 会变成 1,等等。不会出现 panic,但是结果往往与期望不符。

在实际开发中,不应依赖整数溢出的环绕行为,这被认为是错误的做法。若需要显式处理溢出,可以使用标准库里为整数提供的以下方法族:

  • wrapping_*:如 wrapping_add,始终进行环绕运算;
  • checked_*:如 checked_add,若溢出则返回 None
  • overflowing_*:如 overflowing_add,返回一个元组 (结果, bool),其中 bool 指示是否发生溢出;
  • saturating_*:如 saturating_add,在溢出时结果会自动“饱和”到对应类型的最小或最大值。

2. 浮点数类型(Floating-Point Types)

Rust 提供了两种原生的浮点数类型:f32(32 位)和 f64(64 位)。默认使用 f64,因为在现代 CPU 上,f64f32 速度几乎相当,但精度更高。所有浮点类型都是有符号数。

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

    println!("x = {}, y = {}", x, y);
}

Rust 的浮点数遵循 IEEE-754 标准。

3. 数值运算(Numeric Operations)

Rust 支持常见的数值运算:加法、减法、乘法、除法和取余。需要注意的是,整数除法会向零方向取整(截断小数部分)。示例:

fn main() {
    // 加法
    let sum = 5 + 10;

    // 减法
    let difference = 95.5 - 4.3;

    // 乘法
    let product = 4 * 30;

    // 除法
    let quotient = 56.7 / 32.2;

    // 取余
    let remainder = 43 % 5;

    println!("sum = {}", sum);
    println!("difference = {}", difference);
    println!("product = {}", product);
    println!("quotient = {}", quotient);
    println!("remainder = {}", remainder);
}

如果需要查看 Rust 提供的所有运算符,可以参考 附录 B。

4. 布尔类型(Boolean Type)

布尔类型(bool)只有两个可能的值:truefalse。它所占的大小是 1 个字节。例如:

fn main() {
    let t = true;
    let f: bool = false;

    println!("t = {}, f = {}", t, f);
}

布尔常常用于条件判断(如 if 表达式),后面会在“控制流”一节详述。

5. 字符类型(Character Type)

Rust 的 char 类型是最基础的字母类型,用单引号包裹,支持 Unicode Scalar Value。这意味着它可以表示除 ASCII 之外更多的字符,比如带重音的拉丁字符、中文、日文、韩文、emoji、零宽空格等。例如:

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

    println!("{}, {}, {}", c, z, heart_eyed_cat);
}

Rust 的 char 类型占 4 个字节,对应 Unicode Scalar Value 范围:U+0000 ~ U+D7FFU+E000 ~ U+10FFFF。需要注意的是,Unicode 的“字符”概念可能与人们直觉中的“字符”不完全一致。详情可参考第 8 章关于字符串的讨论。

二、复合类型(Compound Types)

复合类型可以将多个值组合成一个类型。Rust 提供了两种原生的复合类型:元组(tuple)和数组(array)。

1. 元组类型(Tuple Type)

元组(tuple)可以将多个类型各异的值组合到一个复合类型中,长度固定,不可增长或缩短。使用小括号 () 包含并用逗号分隔不同的值。例如:

fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
    println!("tup = {:?}", tup);
}
1.1 解构(Destructuring)元组

要获取元组中的单独值,可以使用模式匹配(pattern matching)进行解构:

fn main() {
    let tup = (500, 6.4, 1);
    let (x, y, z) = tup;

    println!("y = {}", y);
}

执行后,y 的值就是 6.4。这里 tup 被“拆解”成了 x, y, z 三个变量的过程,称为解构

1.2 使用索引访问元组

也可以直接用点号加索引来访问元组的指定元素:

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;

    println!("{}, {}, {}", five_hundred, six_point_four, one);
}

需要注意,索引从 0 开始。

1.3 单元类型(Unit Type)

如果元组不包含任何元素,则被称为单元元组(unit)。它写作 (),表示一种空值或空的返回类型。若一个表达式没有返回任何其他值,默认会返回单元元组。

2. 数组类型(Array Type)

数组(array)也是一种把多个值组合在一起的方式,但它与元组有两个主要区别:

  1. 数组中所有元素类型相同
  2. 数组长度固定,一旦声明,长度就无法改变。

例如:

fn main() {
    let a = [1, 2, 3, 4, 5];
    println!("{:?}", a);
}

数组通常存储在上(stack)而不是堆上(heap),这在 第 4 章 会详细解释。若需要一个可伸缩的序列,则使用标准库提供的 向量vectorVec<T>)。如果你需要一个长度固定的序列,数组就非常合适。比如月份名称:

let months = [
    "January", "February", "March", "April", "May", "June",
    "July", "August", "September", "October", "November", "December"
];
2.1 数组的类型注解

声明数组类型时,需要在方括号里写元素类型、分号、元素个数:

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

这里 i32 是每个元素的类型,5 表示数组长度。

2.2 初始化为相同元素

如果想让数组的所有元素都相同,可以使用如下语法:

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

可以使用索引来访问数组元素:

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

    let first = a[0];
    let second = a[1];

    println!("first = {}, second = {}", first, second);
}
2.4 越界访问与运行时错误

如果索引超出了数组的长度,Rust 会在运行时检查到错误并 panic:

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

    println!("请输入一个数组索引。");
    let mut index = String::new();

    std::io::stdin()
        .read_line(&mut index)
        .expect("读取失败");

    let index: usize = index
        .trim()
        .parse()
        .expect("输入的索引不是数字");

    let element = a[index];

    println!("你选择的元素是:{}", element);
}

如果你输入了超出 [0..4] 范围的索引,比如 10,就会引发 panic,显示类似:

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

程序因此退出并不会执行后续的 println!。这是 Rust 保证内存安全的体现:许多低级语言在越界索引时可能会访问非法内存地址,引发不可预料的后果,而 Rust 直接在运行时检测并退出以保证安全。

小结

在本篇文章中,我们介绍了 Rust 最常用的两种数据类型子集:标量类型复合类型。标量类型包括整数、浮点数、布尔和字符,它们各自有不同的表示和范围;复合类型包括元组和数组,可以用于将多个值组合到一个类型中,并且在长度是否可变和类型一致性方面有所区别。

  • 标量类型

    • 整数:如 i32, u32, i8, u8 等,不同字长和有符号/无符号选择;
    • 浮点数f32f64,默认使用 f64
    • 布尔bool,仅有 truefalse
    • 字符char,占 4 字节,可表示 Unicode Scalar Value。
  • 复合类型

    • 元组:可含多种类型,长度固定;可用解构或索引方式访问;
    • 数组:同类型元素的集合,长度固定,存储于栈上。

对于新手而言,遇到无法自动推断类型的情形时,需要加上类型注解,尤其是在使用 parse 或其他需要指明具体数值类型的场景下。随着实践的深入,Rust 提供的多种安全检查机制(如整数溢出检查、数组越界检查等)会给予你更多信心和安全感,同时也需要你熟悉这些机制以写出高效且安全的代码。

在后续章节中,我们将会不断深入 Rust 的特性,包括所有权、引用与切片、集合类型(向量、字符串、哈希映射)以及错误处理等,希望你能继续保持对 Rust 的探索与学习。

参考与致谢

  • The Rust Programming Language - By Steve Klabnik and Carol Nichols, CC BY 4.0
  • 本文部分内容基于其翻译和改写,如需了解更多细节,请阅读官方文档。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2279631.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI可信论坛亮点:合合信息分享视觉内容安全技术前沿

前言 在当今科技迅猛发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;技术正以前所未有的速度改变着我们的生活与工作方式。作为AI领域的重要盛会&#xff0c;CSIG青年科学家会议AI可信论坛汇聚了众多青年科学家与业界精英&#xff0c;共同探讨AI技术的最新进展、挑…

调试Hadoop源代码

个人博客地址&#xff1a;调试Hadoop源代码 | 一张假钞的真实世界 Hadoop版本 Hadoop 2.7.3 调试模式下启动Hadoop NameNode 在${HADOOP_HOME}/etc/hadoop/hadoop-env.sh中设置NameNode启动的JVM参数&#xff0c;如下&#xff1a; export HADOOP_NAMENODE_OPTS"-Xdeb…

Ability Kit-程序框架服务(类似Android Activity)

文章目录 Ability Kit&#xff08;程序框架服务&#xff09;简介Stage模型开发概述Stage模型应用组件应用/组件级配置UIAbility组件概述概述声明配置 生命周期概述生命周期状态说明Create状态WindowStageCreate**和**WindowStageDestroy状态WindowStageWillDestroy状态Foregrou…

鸿蒙安装HAP时提示“code:9568344 error: install parse profile prop check error” 问题现象

在启动调试或运行应用/服务时&#xff0c;安装HAP出现错误&#xff0c;提示“error: install parse profile prop check error”错误信息。 解决措施 该问题可能是由于应用使用了应用特权&#xff0c;但应用的签名文件发生变化后未将新的签名指纹重新配置到设备的特权管控白名…

哈尔滨有双线服务器租用吗?

哈尔滨有双线服务器租用吗&#xff1f;双线服务器是一种针对哈尔滨特有的网络环境优化的服务器解决方案&#xff0c;它能够同时支持中国电信和中国联通或移动其中两家主要ISP&#xff08;互联网服务提供商&#xff09;的连接。 由于中国南方地区多采用电信网络&#xff0c;而北…

三天急速通关Java基础知识:Day1 基本语法

三天急速通关JAVA基础知识&#xff1a;Day1 基本语法 0 文章说明1 关键字 Keywords2 注释 Comments2.1 单行注释2.2 多行注释2.3 文档注释 3 数据类型 Data Types3.1 基本数据类型3.2 引用数据类型 4 变量与常量 Variables and Constant5 运算符 Operators6 字符串 String7 输入…

JVM 面试八股文

目录 1. 前言 2. JVM 简介 3. JVM 内存划分 3.1 为什么要进行内存划分 3.2 内存划分的核心区域 3.2.1 核心区域一: 程序计数器 3.2.2 核心区域二: 元数据区 3.2.3 核心区域三: 栈 3.2.4 核心区域四: 堆 4. JVM 类加载机制 4.1 类加载的步骤 4.1.1 步骤一: 加载 4…

《AI赋能中国制造2025:智能变革,制造未来》

引言&#xff1a;开启智能制造新时代 在全球制造业格局深度调整的当下&#xff0c;科技变革与产业转型的浪潮汹涌澎湃。2015 年&#xff0c;我国重磅推出《中国制造 2025》这一宏伟战略&#xff0c;它如同一座灯塔&#xff0c;为中国制造业驶向高端化、智能化、绿色化的彼岸指明…

Observability:最大化可观察性 AI 助手体验的 5 大提示(prompts)

作者&#xff1a;来自 Elastic Zoia_AUBRY 在过去三年担任客户工程师期间&#xff0c;我遇到了数百名客户&#xff0c;他们最常问的问题之一是&#xff1a;“我的数据在 Elastic 中&#xff1b;我该如何利用它获得最大优势&#xff1f;”。 如果这适用于你&#xff0c;那么本…

Mysql常见问题处理集锦

Mysql常见问题处理集锦 root用户密码忘记&#xff0c;重置的操作(windows上的操作)MySQL报错&#xff1a;ERROR 1118 (42000): Row size too large. 或者 Row size too large (&#xff1e; 8126).场景&#xff1a;报错原因解决办法 详解行大小限制示例&#xff1a;内容来源于网…

【前端】用OSS增强Hexo的搜索功能

文章目录 前言配置 _config.fluid.yml云端实时更新 local-search.xml解决 OSS.Bucket 的跨域问题 前言 原文地址&#xff1a;https://blog.dwj601.cn/FrontEnd/Hexo/hexo-enhance-local-search-with-oss/ 考虑到某著名云服务商提供的云服务器在两年的 99 计划后续费价格高达四…

ROS2 与机器人视觉入门教程(ROS2 OpenCV)

系列文章目录 前言 由于现有的ROS2与计算机视觉&#xff08;特别是机器人视觉&#xff09;教程较少&#xff0c;因此根据以往所学与积累的经验&#xff0c;对ROS2与机器人视觉相关理论与代码进行分析说明。 本文简要介绍了机器人视觉。首先介绍 ROS2 中图像发布者和订阅者的基…

02内存结构篇(D1_自动内存管理)

目录 一、内存管理 1. C/C程序员 2. Java程序员 二、运行时数据区 1. 程序计数器 2. Java虚拟机栈 3. 本地方法栈 4. Java堆 5. 方法区 运行时常量池 三、Hotspot运行时数据区 四、分配JVM内存空间 分配堆的大小 分配方法区的大小 分配线程空间的大小 一、内存管…

C#,入门教程(01)—— Visual Studio 2022 免费安装的详细图文与动画教程

通过本课程的学习&#xff0c;你可以掌握C#编程的重点&#xff0c;享受编程的乐趣。 在本课程之前&#xff0c;你无需具备任何C#的基础知识&#xff0c;只要能操作电脑即可。 不过&#xff0c;希望你的数学不是体育老师教的。好的程序是数理化的实现与模拟。没有较好的数学基础…

BGP边界网关协议(Border Gateway Protocol)路由引入、路由反射器

一、路由引入背景 BGP协议本身不发现路由&#xff0c;因此需要将其他协议路由&#xff08;如IGP路由等&#xff09;引入到BGP路由表中&#xff0c;从而将这些路由在AS之内和AS之间传播。 BGP协议支持通过以下两种方式引入路由&#xff1a; Import方式&#xff1a;按协议类型将…

【Vim Masterclass 笔记21】S09L39:Vim 设置与 vimrc 文件的用法示例(二)

文章目录 S09L39 Vim Settings and the Vimrc File - Part 21 Vim 的配色方案与 color 命令2 map 命令3 示例&#xff1a;用 map 命令快速生成 HTML 代码片段4 Vim 中的 Leader 键5 用 mkvimrc 命令自动生成配置文件 写在前面 本篇为 Vim 自定义配置的第二部分。当中的每个知识…

owasp SQL 注入-03 (原理)

1: 先看一下注入界面: 点submit 后&#xff0c;可以看到有语法报错&#xff0c;说明已经起作用了: 报如下的错误: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near at line 1 2:…

SpringMVC (1)

目录 1. 什么是Spring Web MVC 1.1 MVC的定义 1.2 什么是Spring MVC 1.3 Spring Boot 1.3.1 创建一个Spring Boot项目 1.3.2 Spring Boot和Spring MVC之间的关系 2. 学习Spring MVC 2.1 SpringBoot 启动类 2.2 建立连接 1. 什么是Spring Web MVC 1.1 MVC的定义 MVC 是…

LabVIEW 实现线路板 PCB 可靠性测试

在电子设备制造领域&#xff0c;线路板 PCB&#xff08;Printed Circuit Board&#xff09;的可靠性直接影响产品的整体性能和使用寿命。企业在生产新型智能手机主板时&#xff0c;需要对 PCB 进行严格的可靠性测试&#xff0c;以确保产品在复杂环境下能稳定运行。传统的测试方…

【大数据2025】Hadoop 万字讲解

文章目录 一、大数据通识大数据诞生背景与基本概念大数据技术定义与特征大数据生态架构概述数据存储数据计算与易用性框架分布式协调服务和任务调度组件数仓架构流处理架构 二、HDFSHDFS 原理总结一、系统架构二、存储机制三、数据写入流程四、心跳机制与集群管理 安全模式&…