Rust 专题【左扬精讲】—— 变量、常量与标量数据类型

Rust 专题【左扬精讲】—— 变量、常量与标量数据类型

Rust 变量 常量 数据类型 标量类型 多语言对比

学习提醒

  • 必须掌握:Rust 变量默认不可变、mut 关键字、const vs let 区别、整数溢出处理
  • 理解记忆:变量遮蔽(Shadowing)与可变赋值的本质区别、类型推导机制
  • 扩展了解:Rust 与其他语言在可变性、类型系统、安全性上的设计哲学差异

目录


一、注释(Comments)

注释是代码的"隐形文档",对编译器而言如同空气,但它是开发者之间最重要的沟通语言。Rust 的注释语法与大多数主流语言保持一致。

1.1 单行注释

使用 // 开头,行内或独占一行均可,注释内容在 // 之后直到行尾结束。

// Rust
fn main() {
    // 这是一行注释,编译器会忽略它
    let x = 42; // 行尾注释:解释 x 的含义
}

1.2 多行注释

使用 /* 开始、*/ 结束,可以跨越多行,常用于块级说明文档。

/*
  这是一个多行注释
  可以写很长很长的说明内容
*/
fn greet(name: &str) { /* 也可以这样:行内块注释 */ }

1.3 文档注释

Rust 提供了专用的文档注释,支持 Markdown 语法,并能通过 cargo doc 生成 HTML 文档。

/// 计算两个整数的和
///
/// # Examples
/// assert_eq!(add(2, 3), 5);
pub fn add(a: i32, b: i32) -> i32 { a + b }

/**
  结构体的文档注释
  使用 /* */ 包裹多行
*/
pub struct User { name: String }

提示:文档注释 ///(内部项)和 /** ... */ 用于为函数、结构体、模块等生成 API 文档,是 Rust 生态中分享库的重要工具。

设计精髓:Rust 注释的哲学

Rust 的注释设计与它的"清晰优于隐晦"哲学一致。文档注释直接支持 Markdown,这意味着标准库的文档美观且一致。而 ///* */ 的选择更多是风格问题,但在 Rust 中,块注释还常被用于临时禁用代码(配合嵌套特性)。


二、常量(Constants)

常量是程序生命周期内始终保持不变的值。与变量不同,常量永远不可变,没有可变性开关,也不需要运行时检查——编译器在编译期就将常量的值内联到所有引用处,实现零成本抽象。

2.1 直接常量(字面量 / Literals)

直接写在代码中的字面量是最原生的常量形式,不绑定任何名称。

2.2 const 常量定义

Rust 中使用 const 关键字声明编译期常量,类型标注必须显式给出

// Rust
const MAX_RETRIES: u32 = 3;           // const 常量,类型必须标注
const PI: f64 = 3.14159;            // 浮点常量
const GREETING: &str = "你好,世界"; // 字符串常量(生命周期 elided)

// const 还可以在函数内部声明(块作用域)
fn process() {
    const TIMEOUT_MS: u64 = 5000;
    println!("超时: {}ms", TIMEOUT_MS);
}

重要:Rust 的 const 是真正的编译期常量——它的值在编译阶段就完全确定,编译器会做常量折叠(Constant Folding),不会在运行时为常量分配内存。

2.3 多语言对比:常量声明

语言语法类型标注可用位置特殊规则
Rust const NAME: type = value; 必须显式标注 任意作用域(块内/函数内/全局) 仅编译期已知表达式
C #define NAME valueconst type NAME = value; 可选(宏无需标注) 仅文件/全局作用域 宏无类型;const 在 C89 中行为模糊
C++ constexpr type NAME = value;const type NAME = value; 可选(C++11 后推荐 constexpr) 任意作用域 constexpr 保证编译期求值,const 可运行时求值
Python NAME = value(无专门语法,靠约定) 无类型系统(可用 type hints) 模块/类作用域 无真正常量,约定全大写变量名不变
Go const Name type = value 可选(可省略自动推导) 任意作用域 仅支持编译期可确定的常量表达式
Java static final type NAME = value; 必须显式标注 类作用域(字段) static + final 共同修饰,运行时常量
JS const NAME = value; 无类型标注(可用 JSDoc/TS) 块作用域 绑定不可重新赋值,但值本身可能可变
TS const NAME: type = value; 可选(TypeScript 类型标注) 块作用域 编译到 JS const,类型仅在编译期检查

注意:C 语言的 #define 宏:与 Rust 的 const 功能相近但有本质区别。宏是纯文本替换,没有类型、不占内存、不参与调试符号。而 Rust 的 const 有类型系统、参与类型检查、可在调试器中查看。

对比记忆

  • Rust const = C++ constexpr(编译期求值,无运行时开销)
  • Java static final = Rust static(运行时存储在 .rodata 段)
  • Python/JS 没有真正的编译期常量,只能靠约定或运行时检查
  • Go 的 const 与 Rust 设计最接近,但 Go 无 static 关键字

设计精髓:Rust 为什么需要 const + static 两种常量?

  • const:编译期内联,零运行时成本,类似 C 宏但有类型安全
  • static:拥有固定内存地址,生命周期为整个程序运行,可包含需要地址的引用(如 &'static str),但引用的数据必须是 'static 生命周期

三、变量(Variables)

3.1 Rust 关键字

Rust 有一套保留关键字(Reserved Keywords),它们在语言中有特殊含义,不能用作标识符(变量名、函数名等)。关键字分为两类:

  • 纯关键字(Strict Keywords):在任何上下文中都不能作为标识符,如 asbreakconstiflet
  • 严格关键字(Reserved Keywords):当前未使用,但为未来扩展保留,如 abstractasyncawaitdyntry
// Rust 关键字示例 —— 下列名称都不能用作变量名
// let, fn, if, else, for, while, loop, match, struct, enum,
// impl, trait, pub, mod, use, crate, self, super, async, await,
// return, move, ref, mut, dyn, where, type, as, in,
// break, continue, Self, static, unsafe, extern

// raw identifier: 用 r# 前缀可以在特殊场景下使用关键字作标识符
let r#if = 42; // 合法:raw identifier 语法 r#keyword

3.2 变量命名规则

Rust 的命名规范与大多数主流语言相似,但 Rust 社区有强烈的命名文化偏好:

规则说明
字母或下划线开头 不能以数字开头,如 2name 非法
驼峰命名法(变量/函数) Rust 约定用下划线分隔(snake_case):my_variable
全大写+下划线(常量) MAX_SIZEPI_VALUE
避免单字母大写(L 类型) 由于 IO 易与数字 1、0 混淆,Rust 不允许
UTF-8 命名 Rust 支持 Unicode 标识符,可用中文命名(如 let 名字 = "Rust";

3.3 变量定义与初始化

Rust 使用 let 关键字声明变量。与大多数语言不同,Rust 的变量默认是不可变的——这是语言设计中最核心的理念之一:安全性优先于便利性。

3.3.1 定义(声明)

// Rust:声明与初始化通常一起进行
let x: i32;           // 声明(无初始化,类型标注可选)
x = 10;               // 后续赋值:OK,未初始化的变量必须先赋值再使用

// 声明+初始化:最常见写法,类型可由右侧推导
let name: String = String::from("Alice");
let score = 100;      // 类型由字面量推导为 i32

3.3.2 多语言对比:变量声明与初始化

语言声明语法类型推导默认可变未初始化使用
Rust let x: i32; 支持(右侧推导) 否,默认不可变 编译错误(安全)
C int x; 不支持 未定义行为(危险!)
C++ int x; C++11 auto 未定义行为(危险!)
Python x = 10(无需声明) 强推导(动态类型) 是(但变量可重新绑定) NameError(运行时常量)
Go x := 10var x int := 自动推导 编译错误(零值初始化)
Java int x; var x = 10(Java 10+) 编译错误
JS let x = 10; 支持(但推导结果常为 number) 是(var/let),否(const) undefined(隐式 undefined)
TS let x: number = 10; 支持(类型推断) 是(let),否(const) undefined

重要:C/C++ 的未初始化变量陷阱:在 C 和 C++ 中,使用未初始化的变量是未定义行为(Undefined Behavior),程序可能输出随机垃圾值,甚至导致安全漏洞。Rust 在编译期就消除了这个隐患——如果编译器检测到使用未初始化变量,会直接报错。

3.4 可变性(Mutability)

Rust 用 mut 关键字显式声明变量的可变性。这是 Rust 与众不同的设计:默认不可变,需要时才开放可变权限

// Rust:默认不可变,尝试修改会编译失败
let x = 5;
x = 6; // error[E0384]: cannot assign twice to immutable variable `x`

// 添加 mut:显式声明为可变变量
let mut y = 5;
y = 6; // OK: mut 允许重新赋值
println!("y = {}", y); // 输出: y = 6

设计思考:Rust 选择"默认不可变"而非"默认可变",是受函数式语言影响的决策。这使得多线程代码中大量潜在的数据竞争(Data Race)在编译期就被消灭,同时让代码的意图更加明确——阅读者无需猜测某个变量是否会被修改。

3.4.1 多语言对比:可变与不可变

语言默认行为声明不可变声明可变
Rust 不可变(默认安全) let x = 5; let mut x = 5;
C 可变(无保护) 无原生语法(用 const 限制) int x = 5;
C++ 可变 const int x = 5; int x = 5;(或 int& x
Python 可变(一切皆对象) 无(靠约定) 直接赋值改变对象内容
Go 可变(默认) 无原生语法 x := 5(默认)
Java 可变(字段/局部变量) final int x = 5; int x = 5;
JS 可变(var/let) const x = 5; let x = 5;
TS 可变(let) const x = 5; let x = 5;

对比记忆口诀

  • Rust = 默认安全:不可变是默认态,mut 是例外(类似 Kotlin 的 val vs var,但 Kotlin 是面向对象的)
  • Java = 字段可变final 修饰字段才是常量(与 Rust 相反)
  • Python = 无约束:没有真正的不可变变量,任何变量都可以重新绑定
  • JS/TS = const 是绑定不变:ES6 引入的 const 与 Rust 设计最接近
  • C++ constexpr = Rust const,但 C++ 默认可变

3.5 变量遮蔽(Shadowing)

Rust 允许在同一个作用域内,用 let 重新声明同名变量,这称为变量遮蔽(Shadowing)。被遮蔽的旧变量在内存中仍然存在(若实现了 Drop 则被 drop),新变量占据新的栈帧位置。

// Rust:变量遮蔽 —— 用 let 重新声明同名变量
let x = 5;
println!("x = {}", x);  // x = 5

let x = x + 1;          // 遮蔽:x 从 i32 变为新值(类型相同,可不同)
println!("x = {}", x);  // x = 6

let x = "hello";        // 遮蔽:类型从 i32 变为 &str(类型也可改变!)
println!("x = {}", x);  // x = hello

注意:变量遮蔽 vs 可变赋值 —— 核心区别

  • 遮蔽(Shadowing):用 let 创建全新变量,旧变量被遮蔽,可以改变类型
  • 可变赋值(Mutation):用 mut 修改已有变量的值,类型保持不变,占用同一内存位置

3.5.1 多语言对比:变量遮蔽

语言是否支持同名遮蔽语法类型可变化吗
Rust 支持(用 let) let x = ...; let x = ...; 是(可以改变类型)
C 不支持(编译错误)
C++ 支持(内层块可遮蔽外层) 嵌套 { } 块内声明同名 否(类型固定)
Python 支持(无块作用域限制) 直接 x = ... 重新绑定 是(动态类型)
Go 支持(短声明 := 在不同作用域) 嵌套块内的 := 否(类型固定)
Java 不支持(同一作用域重复声明编译错误)
JS let/const 不支持;var 部分支持(函数作用域提升) var 在函数内可重复声明 否(var 无类型)
TS let/const 不支持(同一块作用域) 块级作用域内不允许重复声明 否(静态类型)
我的理解:Rust 变量遮蔽的设计意图

Rust 的变量遮蔽不是为了方便改值(改值应该用 mut),而是为了:

  • 值转换场景:对某个值做一系列不可变的变换操作,每次变换后绑定新变量名,逻辑更清晰
  • 类型适配:可以用不同类型遮蔽同一名称(这在需要类型推导的场景中非常有用)
  • 避免命名污染:不必为中间变量取不同的名字,如 let spaces = spaces.trim()

本质是 let 声明的是新变量,不是"对已有变量重新赋值",这是它与 mut 的根本区别。

3.6 字符串变量(String)

Rust 中字符串是理解难度较高的部分,因为它区分了两种类型:字符串切片 &str拥有所有权的字符串 String

// &str:字符串切片,borrowed view(借阅视图)
let s1: &str = "hello world";  // 字面量 &str,存储在二进制中,static 生命周期

// String:拥有所有权的堆字符串,可变
let s2 = String::from("hello");
let s3 = "hello".to_string();  // 同样创建 String

// 可变 String
let mut s4 = String::from("hello");
s4.push_str(", world!");       // OK: 可变 String,可以追加内容
println!("{}", s4);             // hello, world!

3.6.1 多语言对比:字符串类型

语言可变字符串不可变字符串字符串存储
Rust String(堆,可变) &str(切片,借用) UTF-8 编码
C char[] 数组(栈,需手动管理) char* 指针(字符串字面量在 .rodata) 无统一字符串类型,靠 char* + 长度约定
C++ std::string(可变) const char* / std::string_view ISO-8859-1 或 UTF-16(取决于编译器)
Python 无(字符串不可变) str(不可变) Unicode(Python 3 全部是 Unicode)
Go string(不可变,但 []byte/rune 可变) string 本身不可变 UTF-8 编码
Java StringBuffer / StringBuilder String(不可变) UTF-16(内部 char[])
JS 无(字符串不可变) string(不可变 primitive) UTF-16 编码
TS 无(字符串不可变) string(不可变 primitive) UTF-16 编码(继承 JS)

关键记忆点

  • Rust 的 &str ≈ Go 的 string(但 Go 的 string 不可变)
  • Rust 的 String ≈ C++ 的 std::string(但 Rust 的所有权模型更严格)
  • Python/JS 的字符串是不可变的——这是为了线程安全和字符串驻留(Interning)优化
  • Java 的 String 同样不可变(安全性 + 哈希缓存),可变操作需要 StringBuilder

四、标量数据类型(Scalar Data Types)

Rust 的数据类型分为两大类:标量类型(Scalar)复合类型(Compound)。标量类型是语言中最基础的数据表示,代表一个单一的值。

4.1 数据类型总览

分类Rust 类型说明
整数 有符号:i8, i16, i32, i64, i128, isize 可表示负数(-2^(n-1) ~ 2^(n-1)-1)
无符号:u8, u16, u32, u64, u128, usize 只能表示非负数(0 ~ 2^n-1)
浮点数 f32(IEEE-754 单精度),f64(IEEE-754 双精度) f64 是默认类型(等价 C double / JS number)
布尔值 bool 值:truefalse(占用 1 字节)
字符 char Unicode 标量值,4 字节(UTF-32),可表示 emoji / 中文
单元类型 ()(unit / 空元组) 无返回值的函数的隐式返回类型

4.2 整型(Integer Types)

4.2.1 有符号 vs 无符号整数

// Rust 整数字面量可以加类型后缀,也可以由上下文推导
let decimal    = 98_222;           // 十进制,支持 _ 分隔符(可读性)
let hex        = 0xff;             // 十六进制
let octal      = 0o77;             // 八进制
let binary     = 0b1111_0000;      // 二进制
let byte       = b'A';             // u8 字节字面量(ASCII)

// 类型后缀:明确指定字面量类型
let age: u8   = 30u8;             // 30 as u8
let big: i128 = 1_000_000_000_000i128;

4.2.2 usize / isize

usizeisize 是与机器架构相关的整数类型:

// usize / isize:依赖运行环境的位数
// 64 位机器上 = u64/i64,32 位机器上 = u32/i32
let ptr_size: usize = std::mem::size_of_val("&x");

// 典型用途:数组索引、集合大小、指针运算
let arr = [1, 2, 3, 4, 5];
let len: usize = arr.len(); // len 的类型是 usize

4.2.3 整数溢出处理

这是 Rust 独有的编译模式设计,在 Debug 和 Release 模式下行为不同:

let a: u8 = 255;
// Debug 模式:panic!(触发溢出检测,程序 abort)
// Release 模式:二进制回绕(2's complement wrapping) 255 + 1 = 0

// 更安全的显式溢出处理方法:
let wrapped = a.wrapping_add(1);      // 回绕(任何模式都安全)
let saturating = a.saturating_add(1); // 饱和:超过最大值则取最大值
let checked    = a.checked_add(1);     // 返回 None(溢出)或 Some(value)
let overflow  = a.overflowing_add(1);  // 返回 (result, bool溢出标志)

注意:整数溢出是 C/C++ 中常见的安全漏洞来源。攻击者常常利用缓冲区溢出中整数溢出的组合来绕过安全检查。Rust 的设计让开发者必须显式选择溢出处理策略,而不是依赖未定义行为。

4.2.4 多语言对比:整型

语言i32/u32平台相关默认整数类型溢出行为
Rust 32 位,4 字节 isize/usize(平台指针大小) i32(字面量);f64(浮点默认) Debug=panic;Release=wrapping(需显式选方法)
C 通常 32 位 int 等价平台字长(历史原因) int(但大小不确定,平台相关) 未定义行为(UB)!编译器可自由优化
C++ 继承 C ptrdiff_t / size_t int 未定义行为(UB)
Python 无固定大小(Arbitrary-precision int) —(Python int 是大整数) int(无大小限制,自动扩展) 自动扩展精度,永不溢出
Go int32/uint32 int/uint(平台字长) int(平台相关,通常 64 位) 回绕(wrapping)
Java int(32 位)/ long(64 位) —(Java 无平台相关类型) int 回绕(wrapping),不抛异常
JS —(JS 只有一种 number) —(IEEE-754 双精度) number(IEEE-754 double) 精度丢失(大整数不安全,超过 2^53 会丢失精度)
TS number(继承 JS) number 精度丢失(与 JS 相同)

提示:Python 的大整数 vs Rust 的固定宽度

Python 的 int 可以自动扩展到任意精度(背后是 bignum 实现),但这带来了额外的运行时开销。Rust 的固定宽度整数更接近硬件原生,操作速度极快——代价是需要开发者手动管理溢出风险。

4.3 浮点型(Floating-Point Types)

Rust 有两种浮点类型:f32(IEEE-754 单精度)和 f64(IEEE-754 双精度)。默认使用 f64,因为现代 CPU 上 f64 的计算速度与 f32 几乎相同,且精度更高。

// Rust 浮点字面量
let x = 2.0;           // f64(Rust 默认浮点类型)
let y: f32 = 3.0;      // f32(需显式标注)
let scientific = 1e10;  // 科学计数法:1 * 10^10 = f64

// NaN(Not a Number):非数字检测
let nan = (-1.0).sqrt();  // NaN
println!("{:?}", nan.is_nan());  // true

4.3.1 多语言对比:浮点型

语言单精度双精度默认NaN 行为
Rust f32(IEEE-754) f64(IEEE-754) f64 可比较(is_nan())
C float double double(隐式提升) math.h 中 isnan() 宏
C++ float double double std::isnan()
Python float = C double(IEEE-754) float(单一类型) math.nan, math.isnan()
Go float32 float64 float64 math.IsNaN()
Java float double(默认) double Double.isNaN() / Float.isNaN()
JS number = IEEE-754 double(唯一类型) number Number.isNaN()(注意与全局 isNaN() 区别)
TS number(IEEE-754 double) number Number.isNaN()

对比要点:JS/TS 只有一个 number 类型

JavaScript 和 TypeScript 的 number 类型等价于 IEEE-754 双精度浮点数,没有整数和单精度浮点的区分。这意味着 0.1 + 0.2 !== 0.3(浮点精度问题)在 JS/TS 中同样存在。

4.4 布尔型(Boolean Type)

let is_rust_fun: bool = true;
let is_hard = false;     // 类型推导为 bool

// Rust 的 if 是表达式,可以返回值
let result = if true { 1 } else { 0 }; // result = 1

4.4.1 多语言对比:布尔型

语言布尔字面量布尔大小真值判断零值转换
Rust true / false 1 字节 必须显式比较(无隐式转换) 无隐式转换(if x 非法,需 if x != 0
C 无原生布尔(0=false, 非0=true) 通常 int(4字节) 隐式(整数直接作为条件) 0=false,其他都是 true
C++ true / false(C++11) 1 字节 隐式转换 隐式转换到 int
Python True / False 单例对象 隐式(几乎所有对象都是 truthy) None/0/""/[]/{} 都是 falsy
Go true / false 1 字节(但对齐后 1 字节) 必须显式比较(无隐式转换) 无隐式转换(if x 非法)
Java true / false 理论上 1 位,实际 1 字节 隐式转换(boolean 可直接作为条件) 隐式(if (flag))
JS true / false 单例对象 隐式(truthy/falsy 规则) 0/null/undefined/""/NaN/false 都是 falsy
TS true / false 继承 JS 隐式(truthy/falsy 规则) truthy/falsy 规则

重要设计差异:隐式真值判断

  • Rust/Go 的 if x(x 是整数)—— 编译错误,强制显式比较
  • C/C++/Python/JS 的 if x(x 是整数)—— 合法,依赖隐式转换
  • Rust 和 Go 选择了更严格的类型安全,代价是代码稍微冗长一些

4.5 字符型(Character Type)

Rust 的 char 是完整的 Unicode 标量值(Unicode Scalar Value),占 4 字节,可以表示任何 Unicode 字符,包括中文汉字、emoji、数学符号等。

let c1: char = 'A';           // ASCII 字符
let c2 = '中';                // Unicode 中文(char 可以存中文!)
let c3 = '😂';                // emoji(Unicode Scalar Value)

// char 不是 Rust 中最常用的字符串类型,字符串切片 &str 更常用
println!("'{}' is {} bytes", c3, std::mem::size_of_val(&c3)); // 4 bytes

4.5.1 多语言对比:字符型

语言字符类型大小编码中文支持
Rust char(Unicode 标量值) 4 字节(UTF-32) Unicode Scalar Value 完整支持(emoji/汉字/数学符号)
C char(1 字节) 1 字节 平台编码(通常 ASCII/Latin-1) 无原生支持(需 multibyte / wchar_t)
C++ char / char16_t / char32_t / wchar_t 平台相关 char16_t=UTF-16; char32_t=UTF-32 char16/32_t 支持,char 不支持
Python str 中的单个字符是 str(Unicode) 可变(UTF-8 存储) Unicode(Python 3) 完整支持
Go rune(= int32,Unicode 码点) 4 字节(rune) UTF-8 存储 完整支持
Java char(2 字节) 2 字节(UTF-16 码元) UTF-16(基本多语言平面) 支持(BMP 内的中文)
JS 无 char 类型,字符串是 primitive UTF-16 编码 UTF-16 支持(但代理对问题)
TS 无 char 类型(string) UTF-16 UTF-16 支持

Rust char vs Go rune vs Java char:三个都是 Unicode 标量值,但存储方式不同

Rust 的 char 占用 4 字节存储一个完整的 Unicode 标量值(最大到 U+10FFFF),是内存换便利的设计。Go 的 rune 本质上是 int32 的别名,行为相同。Java 的 char 是 UTF-16 码元,对超出 BMP 的字符(如 emoji)需要用代理对(surrogate pair)处理,稍显麻烦。


五、获取变量的字节数

Rust 使用 std::mem::size_of_val() 函数获取值的字节数,以及 std::mem::size_of<T>() 获取类型的字节数。

println!("bool:        {} bytes", std::mem::size_of::());     // 1
println!("char:        {} bytes", std::mem::size_of::());     // 4
println!("i32:         {} bytes", std::mem::size_of::());      // 4
println!("i64:         {} bytes", std::mem::size_of::());      // 8
println!("f64:         {} bytes", std::mem::size_of::());      // 8
println!("&str:        {} bytes (pointer only)", std::mem::size_of::<&str>()); // 16 (ptr+len on 64-bit)

// size_of_val:获取某个具体值的字节数
let text = "你好 Rust";
println!("'{}' is {} bytes", text, std::mem::size_of_val(text));
// 13 bytes (UTF-8: 你=3, 好=3, 空格=1, R=1, u=1, s=1, t=1)

5.1 多语言对比:获取类型大小

语言语法示例
Rust std::mem::size_of::<T>()
std::mem::size_of_val(&value)
size_of::() // 4
C sizeof(type)
sizeof expression
sizeof(int) // 通常 4
C++ sizeof(type)
sizeof expression
sizeof(double) // 通常 8
Python sys.getsizeof(obj) sys.getsizeof(42) # 28 (含对象头)
Go unsafe.Sizeof(x) unsafe.Sizeof(int64(0)) // 8
Java Unsafe.ARRAY_XXX_INDEX_SCALE
+ Integer.BYTES
Integer.BYTES // 4
JS 无直接方法(对象在堆中,大小不透明) —(运行时不可知)
TS 无直接方法(编译到 JS) —(编译到 JS,无类型大小概念)

Rust 的 size_of_val 揭示了 UTF-8 的高效性:

中文字符"你好"在 UTF-8 中每个占 3 字节,共 6 字节;而 Java 的 char[] 每个中文字符占 2 字节(UTF-16),共 4 字节。如果你的应用主要处理 ASCII 文本,UTF-8 非常节省空间(每个字符 1 字节)。


六、总结

本专题核心要点

  • 注释// 单行、/* */ 多行、/// 文档注释
  • 常量const = 编译期内联(零运行时成本);static = 运行时固定地址;无 mut 选项
  • 变量let 声明(默认不可变);let mut 显式可变;变量遮蔽(Shadowing)可以改变类型
  • 标量类型:整型(i/u + 位数)、浮点(f32/f64,默认 f64)、布尔(bool)、字符(char,4字节 Unicode)
  • 设计哲学:Rust 默认不可变、显式类型标注、安全的整数溢出处理、强制显式布尔比较

Rust vs 其他语言的本质区别

维度Rust 特色其他语言对比
默认可变性 不可变(安全优先) C/C++/Go/Java/JS 默认可变;Python 无约束
变量遮蔽 支持(let 重声明,可改变类型) JS(Python) 可改变值/类型;C/Java 不支持同名遮蔽
整数溢出 Debug=panic, Release=wrapping(需显式选方法) C/C++=UB;Java=wrapping;Python=不溢出;JS=精度丢失
未初始化变量 编译错误(安全) C/C++=UB(危险);Go=零值;Python=NameError;JS=undefined
布尔比较 必须显式(无隐式转换) C/C++/Python/JS 允许隐式(if x 合法)
const 语义 编译期求值,零成本内联(类似 C 宏但类型安全) C++ constexpr 类似;Java static final 运行时;JS const 无编译期保证
学完本文后,下一步学什么?
  • 复合类型:元组(Tuple)、数组(Array)、结构体(Struct)、枚举(Enum)
  • 所有权系统:借用(Borrowing)、引用(References)、生命周期(Lifetime)—— Rust 最核心的概念
  • 模式匹配:match 表达式、if let、解构(Destructuring)
  • 泛型基础:泛型函数、Trait 与接口
  • 错误处理Result<T, E> vs Option<T> —— Rust 的显式错误处理哲学

作者:左扬  |  发表于 2026 年  |  水平有限,欢迎指正

posted @ 2026-06-24 02:27  左扬  阅读(2)  评论(0)    收藏  举报