方法1:使用类型系统表达你的数据结构“谁叫他们是程序员,而不是打字员”——@thingskatedid对于来自其他静态类型编程语言(如C++、Go或Java)的人来说,Rust类型系统的基本概念是非常熟悉的。有一系列具有特定大小的整数类型,包括有符号(i8,i16,i32,
“谁叫他们是程序员,而不是打字员” —— @thingskatedid
对于来自其他静态类型编程语言(如 C++、Go 或 Java)的人来说,Rust 类型系统的基本概念是非常熟悉的。有一系列具有特定大小的整数类型,包括有符号(i8, i16, i32, i64, i128)和无符号(u8, u16, u32, u64, u128)。
还有两种整数类型,其大小与目标系统上的指针大小匹配:有符号(isize)和无符号(usize)。Rust 并不是那种会在指针和整数之间进行大量转换的语言,所以这种特性并不是特别相关。然而,标准集合返回它们的大小作为一个 usize(来自 .len()),所以集合索引意味着 usize 值非常常见 —— 从容量的角度来看,这是显然没有问题的,因为内存中的集合不可能有比系统上的内存地址更多的项。
整数类型确实让我们第一次意识到 Rust 是一个比 C++ 更严格的世界 —— 尝试将一个 quart(i32)放入 pint pot(i16)会在编译时产生错误。
let x: i32 = 42;
let y: i16 = x;
error[E0308]: mismatched types
--> use-types/src/main.rs:14:22
|
14 | let y: i16 = x;
| --- ^ expected `i16`, found `i32`
| |
| expected due to this
|
help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit
|
14 | let y: i16 = x.try_into().unwrap();
| ++++++++++++++++++++
这让人感到安心:当程序员进行有风险的操作时,Rust 不会安静地坐视不管。这也早早地表明,尽管 Rust 有更严格的规则,但它也有助于编译器消息指向如何遵守规则的方法。
建议的解决方案是抛出一个问题,即如何处理转换会改变值的情况,关于错误处理
([方法 4])和使用 panic!
([方法 18])我们将在后面有更多的讨论。
Rust 也不允许一些可能看起来“安全”的操作:
let x = 42i32; // Integer literal with type suffix
let y: i64 = x;
error[E0308]: mismatched types
--> use-types/src/main.rs:23:22
|
23 | let y: i64 = x;
| --- ^ expected `i64`, found `i32`
| |
| expected due to this
|
help: you can convert an `i32` to an `i64`
|
23 | let y: i64 = x.into();
| +++++++
在这里,建议的解决方案并没有提出错误处理的方法,但转换仍然需要是显式的。我们将在后面章节更详细地讨论类型转换([方法 6])。
现在继续探讨不出乎意料的原始类型,Rust 有布尔类型(bool
)、浮点类型(f32
, f64
)和单元类型 ()
(类似于 C
的 void
)。
更有趣的是 char
字符类型,它持有一个 [Unicode
值](类似于 Go 的 [rune 类型
])。尽管它在内部以 4 字节
存储,但与 32 位
整数的转换仍然不会有静默转换。
类型系统中的这种精确性迫使你明确地表达你想要表达的内容 —— u32 值与 char 不同,后者又与序列 UTF-8 字节不同,这又与序列任意字节不同,而且需要你准确地指定你的意思1。[Joel Spolsky 的著名博客]文章可以帮助你理解需要哪种类型。
当然,有一些辅助方法允许你在这不同的类型之间进行转换,但它们的签名迫使你处理(或明确忽略)失败的可能性。例如,一个 Unicode
代码点2 总是可以用 32 位
表示,所以 'a' as u32
是允许的,但反向转换就比较复杂了(因为有些 u32 值不是有效的 Unicode 代码点),例如:
Option<char>
,迫使调用者处理失败的情况unsafe
,迫使调用者也使用unsafe
([方法 16])。继续讨论聚合类型,Rust 有:
Arrays
),它们持有单个类型的多个实例,实例的数量在编译时已知。例如 [u32; 4]
是四个连续的 4 字节整数。Tuples
),它们持有多个异构类型的实例,元素的数量和类型在编译时已知,例如 (WidgetOffset, WidgetSize, WidgetColour)
。如果元组中的类型不够独特 —— 例如 (i32, i32, &'static str, bool)
—— 最好给每个元素命名并使用 …Structs
),它们也持有编译时已知的异构类型实例,但是允许通过名称来引用整个类型和各个字段。Tuple structs
)是结构体和元组的杂交体:整个类型有一个名称,但各个字段没有名称 —— 它们通过数字来引用:s.0
, s.1
等。struct TextMatch(usize, String);
let m = TextMatch(12, "needle".to_owned());
assert_eq!(m.0, 12);
这让我们来到了 Rust 类型系统的皇冠上的宝石:枚举(enum
)。
在其基本形式中,很难看出有什么值得兴奋的。与其他语言一样,枚举允许你指定一组互斥的值,可能附带一个数字或字符串值。
enum HttpResultCode {
Ok = 200,
NotFound = 404,
Teap...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!