参考:https://kaisery.github.io/trpl-zh-cn/ch03-02-data-types.htmlhttps://doc.rust-lang.org/book/ch03-02-data-types.html
除了原生数据类型之外,还可以自定义数据类型:structenum;以及可以定义常量:conststatic
这里的原生数据类型都是存储在栈上的,并且当离开作用域时被移出栈。

标量 (scalar)

整型 (int)

  1. 从类型和范围看: | 长度 | 有符号 | 范围 | 无符号 | 范围 | | —- | —- | —- | —- | —- | | 8-bit | i8 | -128 ~ 127 | u8 | 0 ~ 255 | | 16-bit | i16 | -32,768 ~ 32,767 (约正负 3 万,3E4) | u16 | 0 ~ 65,536 (约 6 万,6E4) | | 32-bit | i32 | -2,147,483,648 ~ 2,147,483,647
    (约正负 21 亿,2E9) | u32 | 0 ~ 4,294,967,296 (约 42 亿,4E9) | | 64-bit | i64 | ±9.2E18 | u64 | 0 ~ 1.8E19 | | 128-bit | i128 | ±1.7E38 | u128 | 0 ~ 3.4E38 | | arch | isize | 依赖运行程序的计算机架构:64 或 32 位 | usize | 64 或 32 位 |

每一个有符号的变体可以储存包含从 到 $ 2^{n - 1} - 1$ 在内的数字,这里 n 是变体使用的位数。所以 i8 可以储存从 -(2^7 ) 到 2^7 - 1 在内的数字,也就是从 -128 到 127。无符号的变体可以储存从 0 到 的数字,所以 u8 可以储存从 0 到 2^8 - 1 的数字,也就是从 0 到 255。

  1. 从输入的形式看: | 数字字面值 | 例子 | | —- | —- | | Decimal (十进制) | 98_222 | | Hex (十六进制) | 0xff | | Octal (八进制) | 0o77 | | Binary (二进制) | 0b1111_0000 | | Byte (单字节字符)(仅限于u8) | b'A' |

除 byte 以外的所有数字字面值允许使用类型后缀,例如 57u857f64;同时也允许使用 _ 做为分隔符以方便读数,例如1_000

  1. Rust 的默认整型是 **i32**:它通常是最快的,甚至在 64 位系统上也是。isizeusize 主要作为某些集合的索引。
  2. 整型溢出:Rust Book: data-types | integer-overflow

在 debug 模式编译时,Rust 检查这类问题并使程序 panic (程序因错误而退出)。
在 release 构建中,Rust 不检测溢出,相反会进行一种被称为二进制补码包装(two’s complement wrapping )的操作:256 变成 0257 变成 1,依此类推。
依赖整型溢出被认为是一种错误,即便可能出现这种行为。如果你确实需要这种行为,标准库中有一个类型显式提供此功能,Wrapping

浮点型 (float)

f32f64,分别占 32 位和 64 位。
默认类型是 **f64** ,因为在现代 CPU 中,它与 f32 速度几乎一样,不过精度更高。
注意:Rust 中的浮点型必须带小数点 .,比如 1 是默认 i32,而 1. 默认才是 f64。在基础的加减乘除中,运算符号前后必须是同一类型,如 1+1. 是不允许的。

布尔型 (bool)

truefalse

字符型 (char)

Rust 的 char 类型**'** (单引号)指定,大小为四个字节 (4 bytes),并代表了一个 Unicode 标量值(Unicode Scalar Value),这意味着它可以比 ASCII 表示更多内容。
拼音字母(Accented letters)、单个数字 0-9、中文、日文、韩文等字符,emoji(绘文字)以及零长度的空白字符都是有效的 char 值。
Unicode 标量值包含从U+0000U+D7FFU+E000U+10FFFF 在内的值。

字符串字面值(str)

Rust 的 str 类型**"** (双引号)指定,全称为 string literals,是被硬编码进程序里的字符串值,编译后被储存在二进制文件中,是不可(在程序运行时)变的。
硬编码 是指将可变变量用一个固定值来代替的方法,将数据直接嵌入到程序或其他可执行对象的源代码中,不同于从外部获取数据或在运行时生成数据。 硬编码数据通常只能通过编辑源代码和重新编译可执行文件来修改,尽管可以使用调试器或十六进制编辑器在内存或磁盘上进行更改。
在编译时就知道其内容,所以文本被直接硬编码进最终的可执行文件中。这使得字符串字面值快速且高效。
Rust 的核心语言中只有一种字符串类型:str,即字符串 slice,它通常以被借用的形式出现,&str。而字符串 slice 是一些储存在别处的 UTF-8 编码字符串数据的引用。比如字符串字面值被储存在程序的二进制输出中,字符串 slice 也是如此。
另一种可变的 类型:”String”

复合 (compound)

元组 (tuple)

元组是将多个其他类型的值用 ( ), 组合起来。元组在栈上不一定是连续存储的,也无法遍历 (traverse or iterate) 元组。
元组长度是固定的:一旦声明,其长度不会增大或缩小。
定义与索引:

  1. let tup: (i32, f64, u8) = (500, 6.4, 1); // 定义元组数据
  2. let tup = (500, 6.4, 1); // 类型注解不是必要的
  3. let (x, y, z) = tup; // 使用模式匹配(pattern matching)来解构(destructure)元组值
  4. // 或者使用点号 `.` 后跟值的索引来直接访问,元组的第一个索引值是 0;如果超出索引会 panic
  5. let five_hundred = x.0;
  6. let six_point_four = x.1;
  7. let one = x.2;

元组的一些特殊情况:

  1. () 是 unit 类型,属于标量类型,通常作为语句(比如 表达式;)的值,或者函数未标注返回值类型时默认的返回值
  2. (single_element,)(literal) 是不同的类型,前者表示 单元素元组,后者表示 括号中的字面值(类比在表达式外层加括号其实就是指表达式本身:(1+1)1+1 是一样的)
    1. // 创建单元素元组需要一个额外的逗号,这是为了和被括号包含的字面量作区分。
    2. println!("one element tuple: {:?}", (5u32,));
    3. println!("just an integer: {:?}", (5u32)); // 加括号的原因是这个值的描述比较多,把括号里面的内容作为整体,而不是作为元组的元素

    数组 (array)

    数组是将相同类型的值用 [] 组合起来。
    数组的长度是固定的:一旦声明,其长度不会增大或缩小。
    数组每个元素的类型必须相同。
    数组是一整块分配在栈上的连续存储的内存。可以遍历 (traverse or iterate) 数组。
    定义与索引:
    1. let a: [i32; 5] = [1, 2, 3, 4, 5]; // 定义数组,与元组类似
    2. let a = [1, 2, 3, 4, 5]; // 类型注解不是必要的
    3. let a = [3; 5]; // 由于是数组元素是单一的类型,所以可以使用 `[初始值;个数]` 来生成一组元素相同的数组
    4. let a = [3, 3, 3, 3, 3]; // 这个与上面一条等价
    5. let a: [i32; 5] = [3; 5]; // `[初始值;个数]` 的形式也可用在类型注解上
    越界访问会 panic

    切片 (slice)

    “slice”
    1. // 数组与 slice 的例子
    2. use std::mem;
    3. // 此函数借用一个 slice
    4. fn analyze_slice(slice: &[i32]) {
    5. println!("first element of the slice: {}", slice[0]);
    6. println!("the slice has {} elements", slice.len());
    7. }
    8. fn main() {
    9. // 定长数组(类型标记是多余的)
    10. let xs: [i32; 5] = [1, 2, 3, 4, 5];
    11. // 所有元素可以初始化成相同的值
    12. let ys: [i32; 500] = [0; 500];
    13. // 下标从 0 开始
    14. println!("first element of the array: {}", xs[0]);
    15. println!("second element of the array: {}", xs[1]);
    16. // `len` 返回数组的大小
    17. println!("array size: {}", xs.len());
    18. // 数组是在栈中分配的
    19. println!("array occupies {} bytes", mem::size_of_val(&xs));
    20. // 数组可以自动被借用成为 slice
    21. println!("borrow the whole array as a slice");
    22. analyze_slice(&xs);
    23. // slice 可以指向数组的一部分
    24. println!("borrow a section of the array as a slice");
    25. analyze_slice(&ys[1 .. 4]);
    26. // 越界的下标会引发致命错误(panic)
    27. // println!("{}", xs[5]);
    28. }
    打印结果:
    1. first element of the array: 1
    2. second element of the array: 2
    3. array size: 5
    4. array occupies 20 bytes
    5. borrow the whole array as a slice
    6. first element of the slice: 1
    7. the slice has 5 elements
    8. borrow a section of the array as a slice
    9. first element of the slice: 0
    10. the slice has 3 elements