Rust - 数据类型
Rust - 数据类型
Section titled “Rust - 数据类型”一个类型系统定义了编程语言支持的不同类别的值。Rust 是一种静态类型语言,这意味着它必须在编译时知道所有变量的类型。这项强大的特性允许编译器验证代码的正确性,预防大量的错误,并为自动补全和重构等工具提供出色的支持。
虽然你必须在函数签名和结构体中明确指定类型,但编译器通常可以从变量的初始值推断出其类型。这让你能够同时享受到两方面的好处:强大的类型安全,同时又避免了不必要的冗余。
使用 let 声明变量
Section titled “使用 let 声明变量”在 Rust 中,你使用 let 关键字声明变量。默认情况下,变量是不可变的,这是 Rust 的一个关键特性,它有助于编写更安全、更可预测的代码。要创建一个可变变量,你需要使用 let mut 关键字。
fn main() { // 类型由编译器推断 let company = "TechCorp"; // &str (string slice) let rating = 4.5; // f64 (floating-point number) let is_profitable = true; // bool (boolean) let logo = '🦀'; // char (Unicode character)
// 你也可以显式地标注类型 let mut project_count: u32 = 10; // u32 (unsigned 32-bit integer) project_count += 1;
println!("Company: {}", company); println!("Rating: {}", rating); println!("Is Profitable? {}", is_profitable); println!("Logo: {}", logo); println!("Current Projects: {}", project_count);}在上面的示例中,company、rating、is_profitable 和 logo 是不可变的。project_count 是可变的,并且其 u32 类型被显式声明。println! 宏使用了 {} 占位符,它们在执行时会被变量的值替换。
你可以在终端中运行 cargo check 来检查代码的正确性而无需编译。要编译并运行,请使用 cargo run。
代码的输出如下:
Company: TechCorpRating: 4.5Is Profitable? trueLogo: 🦀Current Projects: 11标量类型代表一个单一的值。Rust 有四种主要的标量类型:
- 整数(例如,
5、-10) - 浮点数(例如,
3.14、99.9) - 布尔值(例如,
true、false) - 字符(例如,
'a'、'%'、'π')
整数是没有小数部分的数字。它们可以是有符号的(可以为负、零或正)或无符号的(只能为零或正)。以下是内置的整数类型:
| 大小 | 有符号 | 无符号 |
|---|---|---|
| 8-bit | i8 | u8 |
| 16-bit | i16 | u16 |
| 32-bit | i32 | u32 |
| 64-bit | i64 | u64 |
| 128-bit | i128 | u128 |
| Arch | isize | usize |
isize 和 usize 类型取决于你的程序运行的计算机架构:在 32 位架构上是 32 位,在 64 位架构上是 64 位。它们主要用于集合的索引。
最佳实践:默认的整数类型是 i32,这通常是兼顾速度和兼容性的好选择。在对集合进行索引时使用 usize。仅当你存在特定需求时(例如节省内存或与具有固定大小类型的外部系统进行接口交互时),才使用其他整数类型。
整数溢出发生在你尝试将一个超出类型有效范围的值赋给变量时(例如,将 256 赋值给只能保存 0 到 255 的 u8 类型)。Rust 的行为取决于构建配置文件:
- 调试模式:Rust 会检查整数溢出。如果发生溢出,程序将崩溃并立即退出。这有助于你在开发过程中发现错误。
- 发布模式:Rust 不会检查溢出。相反,它会执行二进制补码环绕。例如,
u8中的256会变成0,257会变成1,以此类推。
如果你需要显式地处理溢出,标准库提供了以下方法:
fn main() { let a: u8 = 255;
// checked_* 方法返回一个 Option<T> let checked_add = a.checked_add(1); // 返回 None,因为它会溢出 let checked_add_ok = a.checked_add(0); // 返回 Some(255)
// wrapping_* 方法执行二进制补码环绕 let wrapping_add = a.wrapping_add(1); // 返回 0
// saturating_* 方法返回该类型的最大或最小值 let saturating_add = a.saturating_add(1); // 返回 255
println!("Checked add (255 + 1): {:?}", checked_add); println!("Checked add (255 + 0): {:?}", checked_add_ok); println!("Wrapping add (255 + 1): {}", wrapping_add); println!("Saturating add (255 + 1): {}", saturating_add);}依赖隐式环绕可能导致意想不到的错误。最佳实践是使用 checked_* 方法并在你预期操作可能溢出时处理 None 情况。
Rust 有两种浮点类型:f32(单精度)和 f64(双精度)。默认类型是 f64,因为在现代 CPU 上,它的速度与 f32 大致相同,但能够提供更高的精度。
fn main() { let pi = 3.14159; // 默认为 f64 let interest_rate: f32 = 0.05; // 显式声明为 f32
println!("Pi is approximately {}", pi); println!("Interest Rate is {}", interest_rate);
// 为了提高可读性,你可以在数值字面量中使用下划线 let large_number = 1_000_000.555_001; println!("A large number: {}", large_number);}重要提示:Rust 不会对数字类型之间执行隐式类型转换。以下代码将无法编译:
// 这将无法编译!fn main() { let my_integer: i32 = 10; // error[E0308]: mismatched types // let my_float: f64 = my_integer;}
// 要修复它,你必须使用 `as` 关键字进行显式转换:fn fixed() { let my_integer: i32 = 10; let my_float: f64 = my_integer as f64; // 这是正确的 println!("Float value: {}", my_float);}布尔值和字符
Section titled “布尔值和字符”布尔类型 bool 有两个可能的值:true 和 false。它最常用于像 if 表达式这样的条件逻辑中。
字符类型 char 是 Rust 最原始的字母类型。它使用单引号指定。重要的是,char 代表一个 Unicode 标量值,这意味着它能表示的远不止 ASCII 字符。一个 char 占用 4 字节大小,可以表示字母、数字、符号,甚至表情符号。
fn main() { let is_learning_rust: bool = true; println!("Are we learning Rust? {}", is_learning_rust);
let letter_a = 'a'; let checkmark = '✅'; println!("A simple letter: {}", letter_a); println!("A checkmark emoji: {}", checkmark);}