Rust 速成课/数据类型

这节课我们将讨论 Rust 的数据类型. Rust 是一门静态类型语言, 也就是说在编译阶段就必须知道所有变量的类型. 我估计很多人会被静态类型, 动态类型, 强类型和弱类型这几个词搞得有点晕啦, 我研究出了一个小方法可以帮助大家快速分辨一门语言的类型, 我们首先假设, 这门语言不允许一个字符串与一个整数相加. 那么, 如果你真的写出了这种代码, 如果在编译的时候报错, 那么是这门语言就是静态类型, 如果能成功编译而在运行的时候报错, 那么它就是动态类型. 一个很简单的例子, 你如果在 Python 里面编写字符串与整数相加的代码, 它是可以被成功编译到字节码的, 所以 Python 就是动态类型语言.

可能有的同学会问: 老师, 在 JavaScript 中字符串与整数是可以相加的呀, 那 JavaScript 是什么类型的语言呢? 很好, 华生, 你发现了盲点. 我们称呼这种语言为弱类型语言. 弱类型语言的一大特点就是隐式的类型转换.

我想再考考大家, C 语言是静态类型语言还是动态类型语言? 3, 2, 1, 静态类型语言没错. 那么 C 语言是强类型语言还是弱类型语言? 我多给一些时间, 让我们从 10 开始倒计时吧. 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 时间到. C 语言是弱类型语言. 因为 C 语言包含隐式的类型转换, 例如, 你编写一个函数, 这个函数返回值是 32 位整型, 但是在代码中你可以 return 一个 64 位整型出去, 编译器会对 return 出去的值做类型转换.

Rust 是静态类型和强类型语言, 记住这一点. 但是, Rust 相比其他语言, 例如 C 或 Java, 有一个特点就是我们不必告诉编译器每个变量的类型, 编译器可以从该变量的值进行自动推导. 所以, 以下两种写法都是正确的:

let s = "Hello World!";
let s: &str = "Hello World!;

Rust 的编译器很聪明, 能帮助你处理一些问题.

整数

我们接下来谈谈 Rust 的标量类型. 标量类型表示单个值, Rust 中有四种标量类型, 分别是整数, 浮点数, 布尔值和字符. Rust 里面有许多不同的整数类型, 根据整数的大小和是否带符号, 可以分为 12 种, 它们分别是

Length Signed Unsigned
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, 它们的长度和你的计算机体系有关, 如果你的计算机是 64 位的, 那么 isize 和 usize 也是 64 位的; 如果你的计算机是 32 位的, 那么 isize 和 usize 就是 32 位的.

整数的类型这么多, 那么, 我们该如何知道要使用哪种类型的整数? 如果你不确定, 那么使用 Rust 的默认设置通常是不错的选择, 整数类型的默认设置为 i32: 即使在 64 位系统上, 这种类型通常也是最快的. 当然, 如果你想让自己编写的程序更加现代化的话, 那我也可以提供几条建议.

  1. 尽量不使用 isize 和 usize, 因为它们的行为是不确定的.
  2. 如果你能确保你的数不会为负数, 那么使用无符号整数, 同时, 优先使用 u32. 因为 u32 无论在 32 位还是 64 位机器上都很快, 但 u64 在 32 位机器上并不是.

浮点数

Rust 对于浮点数也有两种类型, 为 f32 和 f64, 大小分别为 32 位和 64 位. Rust 默认浮点数类型为 f64, 因为在现代 CPU 上, 它的速度与 f32 大致相同, 但精度更高. 因此, 总是建议你优先使用 f64.

这是定义一个浮点数的例子

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

布尔值

与大多数其他编程语言一样, Rust 中的布尔类型具有两个可能的值: true 和 false. 布尔值的大小为 1 个字节, Rust 中的布尔类型使用 bool 指定. 例如:

fn main() {
    let t = true;
    let f: bool = false; // with explicit type annotation
}

字符

Rust 也支持最原始的字符, 它们使用单引号包围, 这与使用双引号的字符串不同. Rust 的 char 类型大小为 4 个字节, 代表 Unicode 标量值.

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

数组

数组是很多语言中一个常见的概念, 在 Rust 中也不例外. 数组拥有固定的长度, 每个数组元素都拥有相同的类型. 例如, 我们可以这么定义一个数组:

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

如你所见, 数组使用一对方括号包围, 内跟数组元素. 我想要问题你一个问题, 看你是否已经掌握了我刚才说的知识. 那么请问, 上述代码中变量 a 的类型是什么? 我给出一些思考时间.

首先, 回忆一下, Rust 中默认的整数类型是 i32, 希望你还记得, 因为我在几分钟前刚说过这句话. 然后, 数组中元素的个数是 5, 所以我们可以说变量 a 的类型是长度为 5 的 i32 数组. 您可以显示的标注上这个类型, 就像下面这样:

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

最后, 我们可以使用索引访问数组中的内容, 就像我这样:

println!("{}", a[0]);