在 Rust 中,Hygienic Macros(卫生宏) 是语言设计的一个重要特性,它确保了宏展开时不会意外地捕获或污染调用者作用域中的变量,从而避免了名称冲突和不可预期的行为。
Rust 的卫生宏(Hygienic Macros)主要通过 语法上下文(Syntax Context)
和 ExpnId
来实现。编译器会为每个宏展开分配一个唯一的扩展 ID(ExpnId),并跟踪标识符的来源和绑定关系。
需要注意的点:
- 并非绝对卫生:Rust 的 macro_rules! 宏在局部变量和标签上是卫生的,但对于其他项(如函数、模块、 trait 等)可能并非完全卫生。例如,宏中引用的外部函数或类型仍需在调用处可见。
- 过程宏(Procedural Macros) 默认是非卫生的(Unhygienic)。过程宏的作者需要自行处理标识符的生成和解析,以避免名称冲突。这意味着编写过程宏时需要更小心。
- 变量
rust通过静态类型来保证类型安全,使用let关键字来绑定变量类型:
fn main() {
let x: i32 = 10;
println!("x: {x}");
// x = 20; // 这里会报错: cannot assign twice to immutable variable
// println!("x: {x}");
}
- 值
以下是基本的内置类型及其字面量
类型 | 字面量 | |
---|---|---|
有符号整数 | i8,i16,i32,i64,i128,isize | -10, 0, 1_1000, 123_i64 |
无符号整数 | u8,u16,u32,u64,u128,usize | 0, 123, 10_u16 |
浮点数 | f32, f64 | 3.14, -10.0e20, 2_f32 |
Unicode标量 | char | ‘a’, ‘α’, ‘∞’ |
布尔值 | bool | true, false |
各类型占用的空间为:
- iN, uN 和 fN 占用 N 位,
- isize 和 usize 占用一个指针大小的空间,
- char 占用 32 位空间,
- bool 占用 8 位空间。
char为何是32位:Unicode 标量值的最大码位是 U+10FFFF。要无损地表示所有这些可能的值,至少需要 21 位。Rust 选择 32 位(4 字节)来确保 char 类型有充足的空间容纳任何 Unicode 字符。
char 表示的是 Unicode 码位,它在内存中固定占用 4 字节。而当 char 被存入字符串(如 String 或 &str)时,Rust 会使用 UTF-8 编码。在 UTF-8 编码下,一个字符可能占用 1 到 4 个字节。char 的 len_utf8() 方法可以查看其 UTF-8 编码的字节长度。
bool 类型为何是 8 位?:这主要是为了内存对齐和访问效率。
- 现代 CPU 通常以字节(8 位)为最小单位进行内存访问。如果只分配 1 位,编译器可能需要生成更复杂的指令来提取和操作特定位,这可能反而会降低效率。
- 直接操作一个字节通常比提取一个位更高效。如果 bool 占 1 位,要读取它的值,CPU 可能需要先读取包含它的整个字节(或字),然后进行位掩码和移位操作才能得到那 1 位的值。直接读取一个字节则省去了这些步骤。
- 虽然在单独处理时 bool 占 1 字节,但当 bool 作为结构体或枚举的一部分时,Rust 编译器会尝试进行位级优化(例如 Option
)。编译器可能会将多个 bool 字段打包到同一个字节中,以节省内存。
- 类型推导
Rust 会根据变量的使用来确定其类型:
fn takes_u32(x: u32) {
println!("u32: {x}");
}
fn takes_i8(y: i8) {
println!("i8: {y}");
}
fn main() {
let x = 10;
let y = 20;
takes_u32(x);
takes_i8(y);
// takes_u32(y);
}
整型默认推导为 i32, 浮点型默认推导为f64
本文发表于 0001-01-01,最后修改于 0001-01-01。
本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。