Rust 数据类型详解
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>一、标量类型(Scalar Types)</li><ul class="second_class_ul"><li>1. 整数类型(Integer Types)</li><li>1.1 整数字面量</li><li>1.2 整数溢出(Integer Overflow)</li><li>2. 浮点数类型(Floating-Point Types)</li><li>3. 数值运算(Numeric Operations)</li><li>4. 布尔类型(Boolean Type)</li><li>5. 字符类型(Character Type)</li></ul><li>二、复合类型(Compound Types)</li><ul class="second_class_ul"><li>1. 元组类型(Tuple Type)</li><ul class="third_class_ul"><li>1.1 解构(Destructuring)元组</li><li>1.2 使用索引访问元组</li><li>1.3 单元类型(Unit Type)</li></ul><li>2. 数组类型(Array Type)</li><ul class="third_class_ul"><li>2.1 数组的类型注解</li><li>2.2 初始化为相同元素</li><li>2.3 访问数组元素</li><li>2.4 越界访问与运行时错误</li></ul></ul><li>小结</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>一、标量类型(Scalar Types)</h2><p>标量类型代表一个单独的值。Rust 中有四大基本标量类型:<strong>整数</strong>(integer)、<strong>浮点数</strong>(floating-point number)、<strong>布尔</strong>(boolean)和<strong>字符</strong>(character)。这几种类型在大多数编程语言中都很常见。</p>
<p class="maodian"></p><h3>1. 整数类型(Integer Types)</h3>
<p>整数(integer)是没有小数部分的数字。在之前的猜数字游戏教程里,我们用到了 <code>u32</code>。这个类型声明表示该值是一个<strong>无符号</strong>(unsigned)32 位整数(如果是有符号类型,会以 <code>i</code> 开头,例如 <code>i32</code>)。</p>
<p>下表展示了 Rust 中所有内置的整数类型,每个类型要么是有符号(signed),要么是无符号(unsigned),并且有明确的位数大小。</p>
<table><tbody><tr><th>长度</th><th>有符号</th><th>无符号</th></tr><tr><td>8-bit</td><td><code>i8</code></td><td><code>u8</code></td></tr><tr><td>16-bit</td><td><code>i16</code></td><td><code>u16</code></td></tr><tr><td>32-bit</td><td><code>i32</code></td><td><code>u32</code></td></tr><tr><td>64-bit</td><td><code>i64</code></td><td><code>u64</code></td></tr><tr><td>128-bit</td><td><code>i128</code></td><td><code>u128</code></td></tr><tr><td>arch</td><td><code>isize</code></td><td><code>usize</code></td></tr></tbody></table>
<ul><li><strong>有符号</strong>(signed)表示数值可能为正也可能为负,所以存储时需要符号位;</li><li><strong>无符号</strong>(unsigned)则只表示非负数(0 或正数),不需要符号位。</li></ul>
<p>对于有符号整数,如果类型是 <code>i8</code>,它可以存储从 -128 到 127 的数值;若是 <code>i16</code>,则范围会相应扩大,以此类推。无符号类型则从 0 起算。例如 <code>u8</code> 能表示 0 到 255。</p>
<p><code>isize</code> 和 <code>usize</code> 根据系统架构的不同而变化:在 64 位架构上是 64 位,在 32 位架构上是 32 位。这些类型常用于根据系统架构进行索引或内存大小计算等场景。</p>
<p class="maodian"></p><h3>1.1 整数字面量</h3>
<p>在 Rust 中可以使用多种形式来表达整数字面量(literal),如下表所示:</p>
<table><tbody><tr><th>数字字面量形式</th><th>示例</th></tr><tr><td>十进制</td><td><code>98_222</code></td></tr><tr><td>十六进制</td><td><code>0xff</code></td></tr><tr><td>八进制</td><td><code>0o77</code></td></tr><tr><td>二进制</td><td><code>0b1111_0000</code></td></tr><tr><td>字节(仅限 <code>u8</code>)</td><td><code>b'A'</code></td></tr></tbody></table>
<blockquote><p>注意:</p></blockquote>
<ul><li>可以在数字中使用下划线 <code>_</code> 作为分隔符来提高可读性,例如 <code>1_000</code> 与 <code>1000</code> 等价。</li><li>如果需要指定类型,可以在数字后面加上类型后缀,比如 <code>57u8</code>。</li></ul>
<p>通常如果不确定该用什么整数类型,<strong>Rust 默认使用 <code>i32</code></strong>。若需要根据系统架构进行索引等场景时,才考虑使用 <code>isize</code> 或 <code>usize</code>。</p>
<p class="maodian"></p><h3>1.2 整数溢出(Integer Overflow)</h3>
<p>假设我们有一个 <code>u8</code> 类型的变量,它能表示的数值范围是 <code></code>。如果尝试将其赋值为 256,就会发生<strong>整数溢出</strong>(integer overflow),导致以下两种行为之一:</p>
<ul><li><strong>调试(debug)模式编译</strong>:Rust 会执行溢出检查,一旦发现溢出,就会在运行时 <strong>panic</strong>(程序崩溃并退出)。</li><li><strong>发布(release)模式编译</strong>:Rust 不做溢出检查,而是进行<strong>二补码环绕</strong>(two’s complement wrapping)。换言之,超出最大可表示值时会“环绕”回最小值。例如,对于 <code>u8</code> 类型,256 会变成 0,257 会变成 1,等等。不会出现 panic,但是结果往往与期望不符。</li></ul>
<p>在实际开发中,不应依赖整数溢出的环绕行为,这被认为是错误的做法。若需要显式处理溢出,可以使用标准库里为整数提供的以下方法族:</p>
<ul><li><code>wrapping_*</code>:如 <code>wrapping_add</code>,始终进行环绕运算;</li><li><code>checked_*</code>:如 <code>checked_add</code>,若溢出则返回 <code>None</code>;</li><li><code>overflowing_*</code>:如 <code>overflowing_add</code>,返回一个元组 <code>(结果, bool)</code>,其中 <code>bool</code> 指示是否发生溢出;</li><li><code>saturating_*</code>:如 <code>saturating_add</code>,在溢出时结果会自动“饱和”到对应类型的最小或最大值。</li></ul>
<p class="maodian"></p><h3>2. 浮点数类型(Floating-Point Types)</h3>
<p>Rust 提供了两种原生的浮点数类型:<code>f32</code>(32 位)和 <code>f64</code>(64 位)。默认使用 <code>f64</code>,因为在现代 CPU 上,<code>f64</code> 与 <code>f32</code> 速度几乎相当,但精度更高。所有浮点类型都是有符号数。</p>
<div class="jb51code"><pre class="brush:plain;">fn main() {
let x = 2.0; // f64
let y: f32 = 3.0;// f32
println!("x = {}, y = {}", x, y);
}</pre></div>
<p>Rust 的浮点数遵循 IEEE-754 标准。</p>
<p class="maodian"></p><h3>3. 数值运算(Numeric Operations)</h3>
<p>Rust 支持常见的数值运算:加法、减法、乘法、除法和取余。需要注意的是,<strong>整数除法</strong>会向零方向取整(截断小数部分)。示例:</p>
<div class="jb51code"><pre class="brush:plain;">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);
}</pre></div>
<p>如果需要查看 Rust 提供的所有运算符,可以参考 附录 B。</p>
<p class="maodian"></p><h3>4. 布尔类型(Boolean Type)</h3>
<p>布尔类型(<code>bool</code>)只有两个可能的值:<code>true</code> 和 <code>false</code>。它所占的大小是 1 个字节。例如:</p>
<div class="jb51code"><pre class="brush:plain;">fn main() {
let t = true;
let f: bool = false;
println!("t = {}, f = {}", t, f);
}</pre></div>
<p>布尔常常用于条件判断(如 <code>if</code> 表达式),后面会在“控制流”一节详述。</p>
<p class="maodian"></p><h3>5. 字符类型(Character Type)</h3>
<p>Rust 的 <code>char</code> 类型是最基础的字母类型,用单引号包裹,支持 Unicode Scalar Value。这意味着它可以表示除 ASCII 之外更多的字符,比如带重音的拉丁字符、中文、日文、韩文、emoji、零宽空格等。例如:</p>
<div class="jb51code"><pre class="brush:plain;">fn main() {
let c = 'z';
let z = 'ℤ';
let heart_eyed_cat = '😻';
println!("{}, {}, {}", c, z, heart_eyed_cat);
}</pre></div>
<p>Rust 的 <code>char</code> 类型占 4 个字节,对应 Unicode Scalar Value 范围:<code>U+0000</code> ~ <code>U+D7FF</code> 和 <code>U+E000</code> ~ <code>U+10FFFF</code>。需要注意的是,Unicode 的“字符”概念可能与人们直觉中的“字符”不完全一致。详情可参考第 8 章关于字符串的讨论。</p>
<p class="maodian"></p><h2>二、复合类型(Compound Types)</h2>
<p>复合类型可以将多个值组合成一个类型。Rust 提供了两种原生的复合类型:<strong>元组</strong>(tuple)和<strong>数组</strong>(array)。</p>
<p class="maodian"></p><h3>1. 元组类型(Tuple Type)</h3>
<p>元组(tuple)可以将多个类型各异的值组合到一个复合类型中,长度固定,不可增长或缩短。使用小括号 <code>()</code> 包含并用逗号分隔不同的值。例如:</p>
<div class="jb51code"><pre class="brush:plain;">fn main() {
let tup: (i32, f64, u8) = (500, 6.4, 1);
println!("tup = {:?}", tup);
}</pre></div>
<p class="maodian"></p><h4>1.1 解构(Destructuring)元组</h4>
<p>要获取元组中的单独值,可以使用模式匹配(pattern matching)进行解构:</p>
<div class="jb51code"><pre class="brush:plain;">fn main() {
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
println!("y = {}", y);
}</pre></div>
<p>执行后,<code>y</code> 的值就是 <code>6.4</code>。这里 <code>tup</code> 被“拆解”成了 <code>x</code>, <code>y</code>, <code>z</code> 三个变量的过程,称为<strong>解构</strong>。</p>
<p class="maodian"></p><h4>1.2 使用索引访问元组</h4>
<p>也可以直接用点号加索引来访问元组的指定元素:</p>
<div class="jb51code"><pre class="brush:plain;">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);
}</pre></div>
<p>需要注意,索引从 0 开始。</p>
<p class="maodian"></p><h4>1.3 单元类型(Unit Type)</h4>
<p>如果元组不包含任何元素,则被称为<strong>单元元组</strong>(unit)。它写作 <code>()</code>,表示一种空值或空的返回类型。若一个表达式没有返回任何其他值,默认会返回单元元组。</p>
<p class="maodian"></p><h3>2. 数组类型(Array Type)</h3>
<p>数组(array)也是一种把多个值组合在一起的方式,但它与元组有两个主要区别:</p>
<ul><li>数组中<strong>所有元素类型相同</strong>;</li><li>数组<strong>长度固定</strong>,一旦声明,长度就无法改变。</li></ul>
<p>例如:</p>
<div class="jb51code"><pre class="brush:plain;">fn main() {
let a = ;
println!("{:?}", a);
}</pre></div>
<p>数组通常存储在<strong>栈</strong>上(stack)而不是堆上(heap),这在 第 4 章 会详细解释。若需要一个可伸缩的序列,则使用标准库提供的 <strong>向量</strong>(vector,<code>Vec<T></code>)。如果你需要一个长度固定的序列,数组就非常合适。比如月份名称:</p>
<div class="jb51code"><pre class="brush:plain;">let months = [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];</pre></div>
<p class="maodian"></p><h4>2.1 数组的类型注解</h4>
<p>声明数组类型时,需要在方括号里写元素类型、分号、元素个数:</p>
<div class="jb51code"><pre class="brush:plain;">let a: = ;</pre></div>
<p>这里 <code>i32</code> 是每个元素的类型,<code>5</code> 表示数组长度。</p>
<p class="maodian"></p><h4>2.2 初始化为相同元素</h4>
<p>如果想让数组的所有元素都相同,可以使用如下语法:</p>
<div class="jb51code"><pre class="brush:plain;">let a = ;
// 等价于 let a = ;</pre></div>
<p class="maodian"></p><h4>2.3 访问数组元素</h4>
<p>可以使用索引来访问数组元素:</p>
<div class="jb51code"><pre class="brush:plain;">fn main() {
let a = ;
let first = a;
let second = a;
println!("first = {}, second = {}", first, second);
}</pre></div>
<p class="maodian"></p><h4>2.4 越界访问与运行时错误</h4>
<p>如果索引超出了数组的长度,Rust 会在<strong>运行时</strong>检查到错误并 panic:</p>
<div class="jb51code"><pre class="brush:plain;">fn main() {
let a = ;
println!("请输入一个数组索引。");
let mut index = String::new();
std::io::stdin()
.read_line(&mut index)
.expect("读取失败");
let index: usize = index
.trim()
.parse()
.expect("输入的索引不是数字");
let element = a;
println!("你选择的元素是:{}", element);
}</pre></div>
<p>如果你输入了超出 <code></code> 范围的索引,比如 10,就会引发 panic,显示类似:</p>
<blockquote><p>thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:19:19</p></blockquote>
<p>程序因此退出并不会执行后续的 <code>println!</code>。这是 Rust 保证内存安全的体现:许多低级语言在越界索引时可能会访问非法内存地址,引发不可预料的后果,而 Rust 直接在运行时检测并退出以保证安全。</p>
<p class="maodian"></p><h2>小结</h2>
<p>在本篇文章中,我们介绍了 Rust 最常用的两种数据类型子集:<strong>标量类型</strong>和<strong>复合类型</strong>。标量类型包括整数、浮点数、布尔和字符,它们各自有不同的表示和范围;复合类型包括元组和数组,可以用于将多个值组合到一个类型中,并且在长度是否可变和类型一致性方面有所区别。</p>
<ul><li><strong>标量类型</strong>:
<ul><li><strong>整数</strong>:如 <code>i32</code>, <code>u32</code>, <code>i8</code>, <code>u8</code> 等,不同字长和有符号/无符号选择;</li><li><strong>浮点数</strong>:<code>f32</code> 和 <code>f64</code>,默认使用 <code>f64</code>;</li><li><strong>布尔</strong>:<code>bool</code>,仅有 <code>true</code> 和 <code>false</code>;</li><li><strong>字符</strong>:<code>char</code>,占 4 字节,可表示 Unicode Scalar Value。</li></ul></li><li><strong>复合类型</strong>:<ul><li><strong>元组</strong>:可含多种类型,长度固定;可用解构或索引方式访问;</li><li><strong>数组</strong>:同类型元素的集合,长度固定,存储于栈上。</li></ul></li></ul>
<p>对于新手而言,遇到无法自动推断类型的情形时,需要加上类型注解,尤其是在使用 <code>parse</code> 或其他需要指明具体数值类型的场景下。随着实践的深入,Rust 提供的多种安全检查机制(如整数溢出检查、数组越界检查等)会给予你更多信心和安全感,同时也需要你熟悉这些机制以写出高效且安全的代码。</p>
<p>在后续章节中,我们将会不断深入 Rust 的特性,包括所有权、引用与切片、集合类型(向量、字符串、哈希映射)以及错误处理等,希望你能继续保持对 Rust 的探索与学习。</p>
<blockquote><p><strong>参考与致谢</strong></p></blockquote>
<ul><li>The Rust Programming Language - By Steve Klabnik and Carol Nichols, CC BY 4.0</li><li>本文部分内容基于其翻译和改写,如需了解更多细节,请阅读官方文档。</li></ul>
<p>到此这篇关于Rust 数据类型详解的文章就介绍到这了,更多相关Rust 数据类型内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li>浅析Rust多线程中如何安全的使用变量</li><li>Rust突破编译器限制构造可修改的全局变量</li><li>2022最新Rust变量与数据类型讲解</li><li>详解Rust中的变量与常量</li><li>Rust语言数据类型的具体使用</li><li>Rust的基础数据类型、变量系统、类型转换以及实战应用</li></ul>
</div>
</div>
<!--endmain-->
頁:
[1]