原生类型

像其他现代编程语言一样,Rust提供了一系列基础的类型,我们一般称之为原生类型。其强大的类型系统就是建立在这些原生类型之上的,因此,在写Rust代码之前,必须要对Rust的原生类型有一定的了解。

bool

Rust自带了bool类型,其可能值为true或者false
我们可以通过这样的方式去声明它:

  1. let is_she_love_me = false;
  2. let mut is_he_love_me: bool = true;

当然,bool类型被用的最多的地方就是在if表达式里了。

char

在Rust中,一个char类型表示一个Unicode字符,这也就意味着,在某些语言里代表一个字符(8bit)的char,在Rust里实际上是四个字节(32bit)。
同时,我们可以将各种奇怪的非中文字符随心所欲的赋值给一个char类型。需要注意的是,Rust中我们要用'来表示一个char,如果用"的话你得到的实际上是一个&'static str

  1. let c = 'x';
  2. let cc = '王';

数字类型

和其他类C系的语言不一样,Rust用一种符号+位数的方式来表示其基本的数字类型。可能你习惯了intdoublefloat之类的表示法,Rust的表示法需要你稍微适应一下。

你可用的符号有 ifu

你可用的位数,当然了,都是2的n次幂,分别为8163264size

你可以将其组合起来,形成诸如i32,u16等类型。

当然了,这样的组合并不自由,因为浮点类型最少只能用32位来表示,因此只能有f32f64来表示。

自适应类型

看完上面你一定会对isizeusize很好奇。这两个是来干啥的。这两个嘛,其实是取决于你的操作系统的位数。简单粗暴一点比如64位电脑上就是64位,32位电脑上就是32位,16位……呵呵哒。

但是需要注意的是,你不能因为你的电脑是64位的,而强行将它等同于64,也就是说isize != i64,任何情况下你都需要强制转换。

数组 array

Rust的数组是被表示为[T;N]。其中N表示数组大小,并且这个大小一定是个编译时就能获得的整数值,T表示泛型类型,即任意类型。我们可以这么来声明和使用一个数组:

  1. let a = [8, 9, 10];
  2. let b: [u8;3] = [8, 6, 5];
  3. print!("{}", a[0]);

和Golang一样,Rust的数组中的N(大小)也是类型的一部分,即[u8; 3] != [u8; 4]。这么设计是为了更安全和高效的使用内存,当然了,这会给第一次接触类似概念的人带来一点点困难,比如以下代码。

  1. fn show(arr: [u8;3]) {
  2. for i in &arr {
  3. print!("{} ", i);
  4. }
  5. }
  6. fn main() {
  7. let a: [u8; 3] = [1, 2, 3];
  8. show(a);
  9. let b: [u8; 4] = [1, 2, 3, 4];
  10. show(b);
  11. }

编译运行它你将获得一个编译错误:

  1. <anon>:11:10: 11:11 error: mismatched types:
  2. expected `[u8; 3]`,
  3. found `[u8; 4]`
  4. (expected an array with a fixed size of 3 elements,
  5. found one with 4 elements) [E0308]
  6. <anon>:11 show(b);
  7. ^
  8. <anon>:11:10: 11:11 help: see the detailed explanation for E0308
  9. error: aborting due to previous error

这是因为你将一个4长度的数组赋值给了一个只需要3长度数组作为参数的函数。那么如何写一个通用的show方法来展现任意长度数组呢?请看下节Slice

Slice

Slice从直观上讲,是对一个Array的切片,通过Slice,你能获取到一个Array的部分或者全部的访问权限。和Array不同,Slice是可以动态的,但是呢,其范围是不能超过Array的大小,这点和Golang是不一样的。

一个Slice的表达式可以为如下: &[T] 或者 &mut [T]

这里&符号是一个难点,我们不妨放开这个符号,简单的把它看成是Slice的甲鱼臀部——规定。另外,同样的,Slice也是可以通过下标的方式访问其元素,下标也是从0开始的哟。
你可以这么声明并使用一个Slice

  1. let arr = [1, 2, 3, 4, 5, 6];
  2. let slice_complete = &arr[..]; // 获取全部元素
  3. let slice_middle = &arr[1..4]; // 获取中间元素,最后取得的Slice为 [2, 3, 4] 。切片遵循左闭右开原则。
  4. let slice_right = &arr[1..]; // 最后获得的元素为[2, 3, 4, 5, 6],长度为5。
  5. let slice_left = &arr[..3]; // 最后获得的元素为[1, 2, 3],长度为3。

怎么样,了解了吧。
那么接下来我们用Slice来改造一下上面的函数

  1. fn show(arr: &[u8]) {
  2. for i in arr {
  3. print!("{} ", i);
  4. }
  5. println!("");
  6. }
  7. fn main() {
  8. let a: [u8; 3] = [1, 2, 3];
  9. let slice_a = &a[..];
  10. show(slice_a);
  11. let b: [u8; 4] = [1, 2, 3, 4];
  12. show(&b[..]);
  13. }

输出

  1. 1 2 3
  2. 1 2 3 4

动态数组 Vec

熟悉C++ STL的同学可能对C++的vector很熟悉,同样的,Rust也提供了一个类似的东西。他叫Vec

在基础类型里讲Vec貌似是不太合适的,但在实际应用中的应用比较广泛,所以说先粗略的介绍一下,在集合类型的章节会有详细讲述。

在Rust里,Vec被表示为 Vec<T>, 其中T是一个泛型。

下面介绍几种典型的Vec的用法:

  1. let mut v1: Vec<i32> = vec![1, 2, 3]; // 通过vec!宏来声明
  2. let v2 = vec![0; 10]; // 声明一个初始长度为10的值全为0的动态数组
  3. println!("{}", v1[0]); // 通过下标来访问数组元素
  4. for i in &v1 {
  5. print!("{}", i); // &Vec<i32> 可以通过 Deref 转换成 &[i32]
  6. }
  7. println!("");
  8. for i in &mut v1 {
  9. *i = *i+1;
  10. print!("{}", i); // 可变访问
  11. }

输出结果:

  1. 1
  2. 123
  3. 234

最原生字符串 str

你可以用str来声明一个字符串,事实上,Rust中,所有用""包裹起来的都可以称为&str(注意这个&,这是难点,不用管他,不是么?),但是这个类型被单独用的情况很少,因此,我们将在下一节着重介绍字符串类型。

函数类型 Functions

函数同样的是一个类型,这里只给大家普及一些基本的概念,函数类型涉及到比较高阶的应用,希望大家能在后面的闭包章节仔细参读

下面是一个小例子

  1. fn foo(x: i32) -> i32 { x+1 }
  2. let x: fn(i32) -> i32 = foo;
  3. assert_eq!(11, x(10));