之所以世界上有很多类型的书, 是因为世界上有很多类型的人, 而每个人都在追求不同类型的知识. --Lemony Snicket

核心思想

Rust会尽可能去满足类型的要求, 但前提是程序足够可靠 (否则将对可能对类型提出要求)

两个类型特性:

  • 类型推断: 根据给定的变量或者表达式, Rust允许省略类型
  • 函数泛型: 单个函数可以处理不同类型的值

常见类型表

常见特性:

  • char ≠ u8
  • u8需要使用字节字面量: b'X'
  • 其他的类型 (比如: 任意精度整数) 可以使用 num crate
  • Rust要求数组索引为usize (用于表示元素数量或者长度通常也使用usize)
  • 字面量类型确定:
  • 显式后缀确定: 43u8
  • 隐式延迟确定: 无后缀字面量, 找到一处可以确定类型的代码 (如果无法确定, 默认使用i32和f64)
  • 下划线分割: 4_323_333_215
类型名称实例链接
i8, i16, i32, i64, i128给定位宽的有符号整数42, -18, 0x400i16, 20_922_789_77
u8, u16, u32, u64, u128给定位宽的无符号整数同上
isize, usize与机器字等长的有/无符号整数
f32, f64浮点数
bool布尔值true, false
charUnicode字符 (4字节)
(char, u8, i32)元组
()"单元" (空源组)
struct S { x: f32, y: f32 }具名字段型结构体 (字段具有名称x和y)[(Rust程序设计) Chapter9-结构体]((Rust程序设计) Chapter9-结构体 "wikilink")
struct T(i32, char)元组型结构体 (字段不具有名称)
struct E;单元型结构体 (无字段)
enum Attend { OnTime, Late(u32) }枚举[(Rust程序设计) Chapter10-枚举和模式]((Rust程序设计) Chapter10-枚举和模式 "wikilink")
Box<Attend>Box: 指向堆中值的具有型指针Box::new(Late(15))
&i32, &mut i32共享引用 和 可变引用
非拥有型指针, 其生命周期不能超出引用目标
StringUTF-8字符串, 动态分配大小
&str对str的引用: 指向UTF-8文本的非拥有型指针
[f64; 4]
[u8; 256]
数组, 固定长度, 元素类型相同
Vec<f64>向量, 可变长度, 元素类型相同
&u8, *mut u8对切片(数组或向量的某部分)的引用, 包含指针和长度
Option<&str>可选值:
1. None: 无值
2. Some(v): 有值, 值为v
Result<u64, Error>可能失败的操作结果:
1. Ok(v): 成功值, v为值
2. Err(e): 失败值, e为失败号
&dyn Any, &mut dyn Read特型对象, 是对任何实现了一组给定方法的值的引用[(Rust程序设计) Chapter11-特型和泛型]((Rust程序设计) Chapter11-特型和泛型 "wikilink")
fn(&str) -> bool函数指针
闭包无显式书写形式闭包|a, b| a * a + b * b

类型特性

类型解析

三种情况:

  1. 通过上下文可以确定唯一类型: 确定类型
  2. 通过上下文存在多义性: 默认使用i32
  3. 无上下文可以判断类型: 调用特定类型的方法时, 编译错误
println!("{}", (-4).abs()); // 编译错误, 原因: 无上下文确定-4的类型, 直接调用方法导致编译错误
println!("{}", i32::abs(-4)); // 编译成功, 原因: 外部函数调用的运算优先级高于-4, 构成了字面值的上下文, rust可以通过该函数解析得到-4的类型为i32

类型转换

三种情况:

  • 范围内类型转换: 遵循相同的位模式
  • 有符号扩展: 符号填充和零填充
  • 有无符号类型转换: 相同的位模式
fn main() {
    assert_eq!(10_i8 as u16, 10_u16); // 范围内转换
    assert_eq!(2525_u16 as i16, 2525_i16); // 范围内转换

    assert_eq!(-1_i16 as i32, -1_i32); // 带符号扩展
    assert_eq!(65535_u16 as i32, 65535_i32); // 填零扩展 (虽然最高位为0)

    // 超出范围: 截断
    assert_eq!(1000_i16 as u8, 232_u8);
    assert_eq!(65535_u32 as i16, -1_i16);

    // 有无符号类型转换: 相同的位模式
    assert_eq!(-1_i8 as u8, 255_u8);
    assert_eq!(255_u8 as i8, -1_i8);
}

运算符优先级

#Rust-point

重点:

  1. 方法调用 > 一元运算符
  2. -4_i32.abs()相当于-(4_i32.abs()) == -4
运算符/表达式结合性
Paths (路径)
Method calls (方法调用)
Field expressions (字段表达式)
Function calls, array indexing (函数调用, 数组索引)
?
Unary (一元运算符): -, *, !, &, &mut
as
*, /, %
+, -
<<, >>
&
^
|
==, !=, <, >, <=, >=需要圆括号
&&
||
.., .=需要圆括号
=, +=,  -=,  =, /=, %=
&=, |=, ^=, <<=, >>=
return break closures(返回、中断、闭包)

3.1 固定宽度数据类型

检查算法 & 回绕算法 & 饱和算法 & 溢出算法

Rust处理整形运算溢出的两种情况:

  1. 调试构建: 引起panic
  2. 发布构建: 回绕算法
名称前缀说明实例
检查运算checkedchecked运算将返回结果的Option值, 数学意义上正确则放回Some(v), 否则返回assert_eq!(10_u8.checked_add(20), Some(30));
assert_eq!(100_u8.checked_add(200), None);
assert_eq!((-128_i8).checked_div(-1), None);
回绕运算wrapping返回"数学意义上正确的结果"对"值域"取模的结果assert_eq!(100_u16.wrapping_mul(200), 20000);
assert_eq!(500_u16.wrapping_mul(500), 53392);
assert_eq!(500_i16.wrapping_mul(500), -12144);
饱和运算saturating返回最接近"数学意义上正确的结果"的值
1. 不存在饱和除法: 整数相除一般不会溢出, 即使溢出也没有"数学意义上正确的结果"
2. 不存在饱和求余: 求余运算不会溢出
3. 不存在饱和位移法: 移位溢出存在多种补救方式, 无法统一支持
assert_eq!(32760_i16.saturating_add(10), 32767);
assert_eq!((-32760_i16).saturating_sub(10), -32768);
溢出运算overflowing返回一个元组(result, overflowed)
result: 回绕值
overflowed: bool值, true表示溢出, false表示未溢出
assert_eq!(5_u16.overflowing_shl(17), (10, true));

特殊运算名称

运算名称后缀例子
加法add100_i8.checked_add(27) = Some(127)
减法sub128_u8.saturating_mul(3) == 255
乘法mul
除法div
求余rem
取负neg
绝对值abs
求幂pow
按位左移shl
按位右移shr

u8

转义字符 (u8)

两种格式: * 字符形式: b'x' * 数值形式: b'\x1b'

转义字符描述示例代码输出
\n换行符let c: u8 = b'\n';换行
\r回车符let c: u8 = b'\r';回车
\t水平制表符let c: u8 = b'\t';制表符
\0空字符(空字节)let c: u8 = b'\0';空字符
\\反斜杠let c: u8 = b'\\';\
\'单引号let c: u8 = b'\'';'
\"双引号(不适用,u8 字节字面量不使用双引号)-
\xNN十六进制 ASCII 字符let c: u8 = b'\x41';A

f32 & f64

类型精度范围
f32IEEE单精度 (至少6位小数)$\displaystyle -3.4 * 10^{38} \sim +3.4 * 10^{38}$
f64IEEE双精度 (至少15位小数)$\displaystyle -1.8 * 10^{308} \sim +1.8 * 10^{308}$

字面量表示:

  • 整数部分
  • 浮点部分
  • 指数部分
  • 规定: 至少存在三个部分中的一个
  • 其他表示: 5.省略后续也可
  • 类型解析默认f64
475

浮点数::特殊关联常量

名称说明
f32::INFINITY无穷大
f32::NEG_INFINITY负无穷大
f32::NAN非数值
f32::MIN最小有限值
f32::MAX最大有限值

标准库运算

方法描述
pow(4)x的四次方
abs()绝对值
count_ones()二进制中位1的个数
fn main() {
    assert_eq!(2_u16.pow(4), 16);
    assert_eq!((-4_i32).abs(), 4);
    assert_eq!(0b101101_u8.count_ones(), 4);
}

3.2 bool类型

Rust对于bool具有非常严格的要求

  • while, if等必须是用bool
  • bool可以转换为整形true = 1, false = 0
  • 其他类型不能转换为bool
  • bool在内存中长度为一个字节, 所以可以拥有指针

3.3 字符类型

char是32位表示的Unicode字符

  • 单独字符: 使用char类型
  • 字符串和文本流使用UTF-8: String使用UTF-8

转义字符 (单引号)

转义字符描述示例代码输出
\'单引号本身let c = '\'';'
\\反斜杠let c = '\\';\
\n换行符let c = '\n';换行
\r回车符let c = '\r';回车
\t水平制表符let c = '\t';制表符
\0空字符(空字节)let c = '\0';空字符
\xNN十六进制 ASCII 字符let c = '\x41';A
\u{NNNN}Unicode 字符(1-6位十六进制)let c = '\u{1F600}';😀

码点表示:

  • 如果码点属于ASCII: 直接写作 '\xHH'
  • 范围更广的表示方法 (Unicode): '\u{HHHHHH}'

两种转换方式:

  1. as: as只执行开销极低且可靠的转换, 由于Unicode的码表范围问题, u16和u32都可能出现非法转换的情况, 所以只有u8可以直接转化为char
  2. 0x32_u8 as char
  3. std::char::from_u32(num: u32)->Option<char>
  4. 非法转换: 返回None
  5. 成功转换: 返回Some(c)

#Rust---

其他细节见: P123

3.4 元组

名称说明
元组定义定义: 各种类型值的元素序列
实例: ("Brazil", 1985)的类型 = (&str, i32)
元组元素访问
#Rust-point
只允许使用常量索引:
t.0: 访问下标为0的元素
t.1: 访问下标为1的元素
常见用法1. 通过元组从函数中返回多个值
fn split_at(&self, mid: usize)->(&str, &str);
2. 使用模式匹配将元组中的每个元素赋值给变量
let (head, tail) = text.split_at(21); // head和tail可以通过类型解析得到其类型为&str
3. 作为羽量级的结构体使用
fn write_image(filename: &str, bounds: (usize, usize)) -> Result<(), std::io::Error>;
零元组 (单元类型)定义: 因为此类型只有一个值所以也称为单元类型()
用法: 用于表示"无值"或者"空值"的情况
fn swap<T>(x: &mut T, y: &mut T); 相当于 fn swap<T>(x: &mut T, y: &mut T) -> ();
尾随逗号在Rust中, 可以使用逗号的地方(数组, 参数, 结构体, 枚举)都可以包含尾随逗号
(&str, i32,)(&str, i32) 相同

1. 让多行列表添加或者删除entry时更加清晰
2. 区分括号表达式和单元素的元组
("hello")为括号表达式中的字符串, ("hello", )为元组

尾随逗号的功能

不使用尾随逗号的多行列表情况: 需要在上一行添加逗号, diff: 修改一行代码 且 新增一行代码, diff不清晰

// 修改前
let items = [
    "apple",
    "banana",
    "cherry"
];

// 修改后
let items = [
    "apple",
    "banana",
    "cherry", // 需要在这里加上逗号
    "date"
];

使用尾随逗号的多行列表情况: 只需要添加新的一行代码, diff只会提示新增一行代码, 更加清晰

// 修改前
let items = [
    "apple",
    "banana",
    "cherry",
];
// 修改后
let items = [
    "apple",
    "banana",
    "cherry",
    "date", // 今天加了一行代码
];

3.5 指针类型

Rust的栈分配和Java的垃圾回收机制区别

具体代码在解释下方

Java下的Rectangle的upperLeft字段是一个引用, 实际的Vector2D对象存储在堆中, 对象内容之间是解耦的. 缺点是:

  • 引用占用了额外的内存
  • 解耦导致内存利用并不紧凑
  • 内存分配和回收需要额外的开销

Rust下的Rectangle将直接嵌套upperLeft字段, 例如Vector2D是(i32, i32), 则Rectangle会嵌套为((i32, i32)(i32, i32)) 优点是:

  • 没有引用占用额外内存
  • 内存利用更加紧凑
  • 无需在堆中分配和回收内存, 减少开销

总结: Rust将内存回收通过所有权机制进行简化, 减少了运行时系统开销.

Java类代码

class Vector2D {
    int x, y;
}

class Rectangle {
    Vector2D upperLeft;
    Vector2D lowerRight;
}

Rust 结构体代码

struct Vector2D {
    x: i32,
    y: i32,
}

struct Rectangle {
    upper_left: Vector2D,
    lower_right: Vector2D,
}

3.5.1 引用

引用类似于指针, 指向一个值的地址, 但是引用最大的特点是: 永远不能为空.

共享引用和可变引用的关系 ≈ 读者和写者

引用类型说明
不可变引用/共享引用数量: 可以同时存在多个 (不能存在可变引用)
权限: 只读
可变引用数量: 只能存在一个 (且共享引用也不能存在)
权限: 读写

3.5.2 Box

Box<T> 是一种用于在堆上分配数据的 智能指针,它提供了对值的所有权和指针语义,并在值超出作用域时自动释放堆内存。Box 是 Rust 中最基础的智能指针之一,常用于需要在堆上存储数据的场景。

堆中分配值最简单的方式就是使用Box::new()

let t = (12, "egg");
let b = Box::new(t); // t类型为(i32, &str), 所以b类型为Box<(i32, &str)>
b超出作用域时, 内存立即释放, 除非b已经被移动 (move)

3.5.3 裸指针

Rust裸指针*mut T, *const T类似于C指针, 裸指针并不安全, 它不会跟踪其指向的内容, 可能为空.

裸指针的解引用只能在unsafe块中执行.

3.6 数组, 向量和切片

三种值序列类型

序列类型代码表示说明
数组[T; N]T表示数组类型
N表示数组长度, 长度在编译阶段确定, 后续无法修改
向量Vec<T>动态分配的可增长的值序列, 元素保存在堆中, 可以随机增加或者减少元素
切片共享切片: &[T]
可变切片: &mut [T]
本质: 数组或者向量的一部分的引用

特性:

  • 共同的方法v.len()都可以得到长度
  • rust会检查下标越界, 如果越界产生panic
  • 数组长度可以是0, 在这种情况下任意索引访问都将产生panic
  • 索引类型必须是usize

3.6.1 数组 (array)

特性说明
数组每一个元素都必须初始化错误代码: let mut a: [u8; 10];: 报错binding declared here but left uninitialized
复杂初始化可以使用iter和迭代器
数组特定填充值将T类型替换为特定类型的填充值, 放在初始值的位置
let mut sieve = [true; 10000];
array调用的方法属于slice所有的使用方法: 遍历, 填充, 排序, 搜索, len()等方法都是slice的方法, 但是Rust会自动将array转化为slice并调用对应的方法

调用流程:
1. Rust隐式生成一个可变切片&mut [i32]
2. 可变切片调用sort()方法

数组声明和初始化

fn main() {
    let lazy_caterer: [u32; 6] = [1, 2, 4, 7, 11, 16]; // 显示指定类型
    // 类型推断: 即推断元素类型, 
    // 同时按照初始化值的最小长度推断数组长度
    let taxonomy = ["Animalia", "Arthropoda", "Insecta"]; 

    assert_eq!(lazy_caterer[3], 7);
    assert_eq!(taxonomy.len(), 3);
}

数组填充

#Rust-point

    let mut sieve = [true; 10000]; // 填充true, 且长度为10000
    for i in 2..100 {
        let mut j = i * i;
        while j < 10000 {
            sieve[j] = false;
            j += i;
        }
    }

    assert!(sieve[211]);
    assert!(!sieve[9876]);

slice的sort()方法

    let mut chaos = [3, 5, 4, 1, 2];
    chaos.sort();
    assert_eq!(chaos, [1, 2, 3, 4, 5]);

3.6.2 向量 (vector)

特性说明
vector定义变长T类型元素的数组 (堆分配)
vector构成1. 指向堆中缓冲区的指针
2. 容量 (capacity)
3. 当前元素个数 (len)
vector创建 (初始化)vec!宏: let mut primes = vec![2, 3, 5, 7];
它提供了一个非常类似于数组的初始化方式

vec!宏填充: vec![0; rows * cols] // 类似数组的填充

迭代器生成: let v: Vec<i32> = (0..5).collect();
注意使用迭代器时需要声明类型, 这样才能知道创建array还是vector

capacity创建: 无需初始化, 因为capacity只是vector的容量, 而不是实际的元素长度, len仍然为0.
let mut v = Vec::with_capacity(2);
vector常用操作添加元素: primes.push(11);
查看当前元素个数: primes.len();
查看容量: primes.capacity();
队尾添加元素: primes.push(1);
队尾弹出元素 (返回的是Option<T>): primes.pop();
插入元素到对应下标: primes.insert(3, 35);
删除对应下标的元素: primes.remove(1);
vector调用的方法属于slicepalindrome.reverse();: 逆序元素排列
vec!宏解释1. 调用Vec::new()创建空vector: let mut pal = Vec::new();
2. 逐个压入数据: pal.push("step");

测试代码 (vector基本使用和常用切片方法)

// fn new_pixel_buffer(rows: usize, cols: usize) -> Vec<u8> {
//     vec![0; rows * cols] // 类似数组的填充操作
// }

fn main() {
    let mut primes = vec![2, 3, 5, 7];
    assert_eq!(primes.iter().product::<i32>(), 210); // 计算所有元素的乘积

    primes.push(11);
    primes.push(13);
    assert_eq!(primes.iter().product::<i32>(), 30_030);

    let mut pal = Vec::new();
    pal.push("step");
    pal.push("on");
    pal.push("no");
    pal.push("pets");
    assert_eq!(pal, vec!["step", "on", "no", "pets"]);

    // let v: Vec<i32> = (0..5).collect();

    // 回文
    let mut palindrome = vec!["a man", "a plan", "a canal", "panama"];
    palindrome.reverse();
    assert_eq!(palindrome, vec!["panama", "a canal", "a plan", "a man"]);

    // 测试len()和capacity()
    let mut v = Vec::with_capacity(2); // 无需初始化, 因为这是vector的capacity, 不是vector的length
    // println!("value = {}", v[0]); 如果为初始化访问元素, Rust会检测越界
    assert_eq!(v.len(), 0);
    assert_eq!(v.capacity(), 2);

    v.push(1);
    v.push(2);
    assert_eq!(v.len(), 2);
    assert_eq!(v.capacity(), 2);

    v.push(3);
    assert_eq!(v.len(), 3);
    println!("capacity now is: {}", v.capacity());

    v.pop();
    assert_eq!(v, vec![1, 2]);
    println!("capacity now is: {}", v.capacity());

    // 插入35到3号位 (后续元素后移)
    let mut v = vec![10, 20, 30, 40, 50];
    v.insert(3, 35);
    assert_eq!(v, vec![10, 20, 30, 35, 40, 50]);

    // 移除1号位的元素
    v.remove(1);
    assert_eq!(v, vec![10, 30, 35, 40, 50]);
}

测试代码 (参数args获取和遍历向量)

fn main() {
    let languages: Vec<String> = std::env::args().skip(1).collect();

    for l in languages {
        println!("{}: {}", l, 
            if l.len() % 2 == 0 {
                "functional"
            } else {
                "imperative"
            }
        );
    }
}

3.6.3 切片 (slice)

#Rust-dif

特性说明
切片的构成是一个"胖指针", 即附带了其他信息的指针:
1. 指向切片首个元素的指针
2. 切牌中元素的数量
切片长度任意的限制1. 切片不能是变量: 如果切片作为变量相当于动态长度的数组 (数组的长度只能是静态的)
2. 切片不能作为参数传递: 切片直接作为参数, 则函数无法获取切片的长度
普通引用, 切片引用, 向量引用, 数组引用的区别
#Rust-point
1. 普通引用: 指向单个值的非拥有型指针
2. 切片引用: 只含有实际数据指针和长度两个部分, 提供对数组或向量的一部分的只读权限, 切片的长度取决于初始化
3. 向量引用: 相比于切片引用多了一个capacity
4. 数组引用: 只能引用整个数组, 不能引用部分

切片内存布局图

    let v: Vec<f64> = vec![0.0, 0.707, 1.0, 0.707];
    let a: [f64; 4] = [0.0, -0.707, 1.0, -0.707];

    let sv: &[f64] = &v;
    let sa: &[f64] = &a;
Pastedimage20250123154147.png

3.7 字符串类型

类似于C++中const char *String两种表示字符串的方式 Rust中也有两种表示字符串的方式

3.7.1 字符串字面量

字符串字面量特性

特性说明代码
双引号表示字符串字面量使用双引号表示, 其中单引号无需转义println!("Hello, world!");
跨越多行字符串字面量可以跨越多行, 且会识别空白符 (空格, 换行)println!("Hello,
world!");
忽略换行和前导空白符println!("Hello,\
world!");
原始字符串Windows路径下需要反斜杠符号, 每次均需要\\转义, 使用原始字符串
特性: 所有空白符和反斜杠包含在字符串中.
r"C:\program files\hello"
原始字符串确定起始问题: 反斜杠转义符失效了, 如果原始字符串中包含"就会导致原始字符串无法确定起始位置
解决方法: 使用**任意数量的#**表示起始位置
r###"Tom say: "Hello!""###

转义字符 (双引号)

转义字符描述示例代码输出
\"双引号本身let s = "\"";"
\\反斜杠let s = "\\";\
\n换行符let s = "\n";换行
\r回车符let s = "\r";回车
\t水平制表符let s = "\t";制表符
\0空字符(空字节)let s = "\0";空字符
\xNN十六进制 ASCII 字符let s = "\x41";A
\u{NNNN}Unicode 字符(1-6位十六进制)let s = "\u{1F600}";😀

3.7.2 字节串 (字节字符串)

字节串特性

特性说明
字节串定义字节串是u8值的切片引用, 而不是Unicode文本
字节串字面量b"GET"类型: &[u8; 3]
字节串与字符串关系1. 字面量语法相似
2. 字面量具有跨越多行, 原始字符串br""的特性
3. 不能包含Unicode, 只能使用ASCII或者\xHH{=tex}

3.7.3 内存中的字符串 (String详细说明)

特性

特性说明
编码格式String采用UTF-8的形式编码
String构成类似于vector:
1. 指向字符串缓冲区的指针
2. 容量 (capacity)
3. 长度 (length): capacity - 1是因为需要'\x00{=tex}'作为字符串结尾标识
注意: 长度以字节而不是字符为单位

其中实际存放UTF-8字符串的缓冲区是可以调整大小的, 可以将String视为Vec<u8> (虽然UTF-8是变长的, 理解为void*)
创建String的方式1. .to_string(): 将&str转换为String: let error_message = "too many pets".to_string();
2. .to_owned(): 同上, 这种方法适用于另一些特定类型
3. format!()宏: 类似于println!(), 返回一个新的String, 而不是文本输出
4. 字符串数组:
let bits = vec!["veni", "vidi", "vici"];
assert_eq!(bits.concat(), "venividivici");
assert_eq!(bits.join(", "), "veni, vidi, vici");
&strstring slice, 胖指针, 构成如下:
1. 指向切片的指针
2. 长度 (length)
&str
&mut str
关系
1. let test = "hello";: test的类型是&str
2. let mut test = "hello";: test的类型也是&str, 但是test本身可以改变, 作为其他的字符串的共享引用
3. let test: &mut str = &mut s;: test的类型时&mut str, 但是能做的事情也不多, 因为切片引用不能修改缓冲区的长度, 只能执行make_ascii_uppercasemake_ascii_lowercase改变大小写
&str
String
功能区别
1. &str更适合函数参数传递

字符串内存实例

    let noodles = "noodles".to_string(); // String
    let oodles = &noodles[1..];
    let poodles = "ಠ_ಠ"; // &str
Pastedimage20250123193110.png

3.7.4 String

String类似于Vec<T>

参数Vec<T>String
自动释放缓冲区
可增长
类型关联函数::new()::with_capacity()
.reverse().capacity()
.push()pop()
范围语法[start..stop]✓, 返回&[T]✓, 返回&str
自动转换&Vec<T>&[T]&String&str
继承的方法来自&[T]来自&str

3.7.5 使用字符串

特性

特性说明代码
支持使用==和!=比较字符串中的内容是否相等assert!("ONE".to_ascii_lowercase() == "one");
还有其他的运算: >, <, <=, >=等

3.7.6 其他类似字符串的类型

类型说明
String&str使用Unicode文本
std::path::PathBuf&Path专用于文件路径
Vec<u8>&[u8]二进制数据
OsString&OsStr操作系统提供的原生形式的环境变量名和命令行参数
std::ffi::CString&CStr和使用 null 结尾字符串的 C 语言库进行互操作

3.8 类型别名

type Bytes = Vec<u8>;

fn decode(data: &Bytes) {
    ...
}

(整理) 各种类型的转义字符

类型代码链接
u8b''[(Rust程序设计) Chapter3-基础数据类型#转义字符 u8]((Rust程序设计) Chapter3-基础数据类型#转义字符 u8 "wikilink")
char''[(Rust程序设计) Chapter3-基础数据类型#转义字符 单引号]((Rust程序设计) Chapter3-基础数据类型#转义字符 单引号 "wikilink")
字符串""[(Rust程序设计) Chapter3-基础数据类型#转义字符 双引号]((Rust程序设计) Chapter3-基础数据类型#转义字符 双引号 "wikilink")

TODO

  • ☐ 类型推断的原理
    • ☐ 出现二义性时如何推断: 编译器会报错
  • ☐ String和&str在什么情况下使用: