惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
GRAHAM CLULEY
博客园_首页
博客园 - Franky
Engineering at Meta
Engineering at Meta
雷峰网
雷峰网
The GitHub Blog
The GitHub Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
C
Cisco Blogs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
宝玉的分享
宝玉的分享
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Full Disclosure
Cloudbric
Cloudbric
J
Java Code Geeks
C
Cybersecurity and Infrastructure Security Agency CISA
Last Week in AI
Last Week in AI
The Hacker News
The Hacker News
量子位
T
The Blog of Author Tim Ferriss
T
Threatpost
Cisco Talos Blog
Cisco Talos Blog
C
Check Point Blog
AWS News Blog
AWS News Blog
Blog — PlanetScale
Blog — PlanetScale
T
Threat Research - Cisco Blogs
Project Zero
Project Zero
Scott Helme
Scott Helme
N
Netflix TechBlog - Medium
A
About on SuperTechFans
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
Tenable Blog
S
Schneier on Security
T
Tor Project blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Hacker News: Ask HN
Hacker News: Ask HN
MongoDB | Blog
MongoDB | Blog
Y
Y Combinator Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Heimdal Security Blog
T
Tailwind CSS Blog
P
Privacy International News Feed
爱范儿
爱范儿
Google DeepMind News
Google DeepMind News
D
DataBreaches.Net
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
博客园 - 叶小钗
人人都是产品经理
人人都是产品经理
The Last Watchdog
The Last Watchdog

博客园 - 左扬

VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— VictoriaLogs 协同:Metrics 到 Logs 的一体化监控 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 源码阅读路线图:如何高效阅读 VM 源码 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 开源生态:VM 在 CNCF 生态中的位置 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 与其他 TSDB 对比:Prometheus/InfluxDB/Thanos/VM VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 写入吞吐/查询延迟/内存占用的数学模型 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 模块依赖图——从 import 语句看组件关系 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— Goroutine 池/atomic/零拷贝/sync.Pool VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 多租户架构——accountID/projectID 与 tenant 隔离 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 版本演进:1.146.0 LTS 重大更新解析 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 整体数据流:一条监控数据的完整生命周期 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— 架构演进:从 TSDB 到 MergeSet 的设计取舍 VictoriaMetrics 1.146.0 源码专题【左扬精讲】—— Single-Node vs Cluster 模式本质区别 VictoriaMetrics 1.146.0 源码【左扬精讲】—— 开篇总览 Rust 专题【左扬精讲】—— 从语法到灵魂:Ownership、Borrowing 与多语言对比 kubernetes 源码【左扬精讲】—— kube-scheduler 启动流程源码分析 Rust 专题【左扬精讲】—— 选择控制语句、运算符与格式化输出 Rust 专题【左扬精讲】—— 所有权详解 Rust 专题【左扬精讲】—— 作用域详解 kubernetes 源码 / Operator 专题【左扬精讲】—— Deployment Controller 源码分析:从对象创建到滚动更新 kubernetes 源码 / Operator 专题【左扬精讲】—— Operator 开发中的 Webhook:从准入控制到生产部署 Kubernetes源码 / Operator 专题【左扬精讲】—— 实现 Application Controller:从零构建生产级控制器 Kubernetes 编程 / Operator 专题【左扬精讲】—— 定义 Application 资源 + 添加自定义新 API 完整指南 Kubernetes 源码【左扬精讲】—— kube-scheduler(调度专题 · 八):内部架构与核心组件 Kubernetes 源码【左扬精讲】—— kube-scheduler(调度专题 · 八): —— 从入口到调度的全链路源码剖析(k8s v1.36.1) DeepSeek-R1 多模态 R1 / VLM-GRPO【左扬精讲】—— Qwen2-VL 微调与视觉推理强化学习实战 DeepSeek-R1 工业 RAG + 微调混合系统【左扬精讲】—— R1 系列收官之作:从 Prompt → RAG → 微调 选型决策树 DeepSeek-R1 推理时扩展【左扬精讲】—— o1 / R1 慢思考机制:Self-Consistency + ToT + PRM 详解 DeepSeek-R1 端侧 LLM 工程【左扬精讲】—— llama.cpp 调参与 Apple Silicon / 国产 NPU / Android 端侧落地全攻略 DeepSeek-R1 vLLM + k8s 生产部署【左扬精讲】—— 从单卡 7B 到 100 卡 671B MoE 集群的工业化部署实战 DeepSeek-R1 评估与系统(Evaluation & Systems)【左扬精讲】—— 从 GSM8K/MMLU 到 LLM-as-Judge 的工业级评估方法论 DeepSeek-R1 模型训练与算法【左扬精讲】—— GRPO 进阶算法:DAPO / PRIME / RLVR / PRM 四大 2025 前沿改进 DeepSeek-R1 模型训练与算法【左扬精讲】—— 数据蒸馏:用 DeepSeek-R1-671B 生成 800K 高质量 CoT 样本的完整流水线 DeepSeek-R1 优化与微调实战【左扬精讲】—— 从 R1 强化学习新范式到 GRPO 微调一站式入门 Kubernetes 源码【左扬精讲】—— kube-scheduler(调度专题 · 七):自定义插件开发实战 —— 手写一个 Score 插件并注册到集群 Kubernetes 源码【左扬精讲】—— kube-scheduler(调度专题 · 六):Scheduler Profile 与多调度器 —— 如何配置多个 profile 实现多租户、Coordinated LeaderElection Kubernetes 源码【左扬精讲】—— kube-scheduler(调度专题 · 五):SchedulingQueue 与 QueueingHint —— 三段队列的细节、v1.36 新引入的 QueueingHint 工作机制 Kubernetes 源码【左扬精讲】—— kube-scheduler(调度专题 · 四):抢占(Preemption)算法剖析 —— DefaultPreemption 如何选 victim、PodDisruptionBudget 如何约束 Kubernetes 源码【左扬精讲】—— kube-scheduler(调度专题 · 二):内置插件逐个精读 — NodeResourcesFit / NodeAffinity / TaintToleration / PodTopologySpread / VolumeBinding / InterPodAffinity Kubernetes 源码 / Operator 专题【左扬精讲】——kube-scheduler(调度专题):调度器内置插件 逐个精读 k8s 源码级精讲(二十六):调度器内置插件逐个精读 Kubernetes 源码 / Operator 专题【左扬精讲】——kube-scheduler(调度专题):调度器内置插件精读 — NodeResourcesFit / NodeAffinity / TaintToleration / PodTopologySpread / VolumeBinding / InterPodAffinity Kubernetes 源码 / Operator 专题【左扬精讲】——kube-scheduler(调度专题):Scheduling Framework 扩展点逐个源码拆解 Kubernetes 源码 / Operator 专题【左扬精讲】——kube-scheduler(调度专题):初识调度模型、内部架构与事件驱动机制 Kubernetes 编程 / client-go 专题【左扬精讲】—— 四种客户端:为什么、怎么选、怎么用 Kubernetes 编程 / Operator 专题【左扬精讲】—— controller-runtime、kubebuilder、operator-sdk 三大框架深度对比 Kubernetes 编程 / Operator 专题【左扬精讲】—— 深入理解 ManagedFields 字段冲突协调机制 Kubernetes 编程 / Operator 专题【左扬精讲】—— k8s Finalizers 深度解析:对象的生命周期与删除控制 Kubernetes 编程 / Operator 专题【左扬精讲】—— OwnerReference 字段与级联删除机制 Kubernetes 编程 / Operator 专题【左扬精讲】—— 深入学习 Server-Side Apply:managedFields 替代 last-applied-configuration 的演进方向 Kubernetes 编程 / Operator 专题【左扬精讲】—— k8s Annotations 与元数据体系(Operator 专题) Kubernetes 编程 / Operator 专题【左扬精讲】—— RESTMapper:把 Group / Version / Kind / Resource 四元组翻译成 REST 路径的"查字典"大师 Kubernetes 编程 / Operator 专题【左扬精讲】—— Converter 资源版本转换器 Kubernetes 编程 / Operator 专题【左扬精讲】—— Application 业务扩展:从单 Deployment 到多 Workload 的复合 Operator 演进 Kubernetes 编程 / Operator 专题【左扬精讲】—— OwnerReference / Finalizer / 准入控制:k8s 资源生命周期的三大支柱 Kubernetes 编程 / Operator 专题【左扬精讲】—— controller-runtime 框架内幕:从 Manager 到 Reconcile 的全栈拆解 Kubernetes 编程 / Operator 专题【左扬精讲】—— 生产级 Operator 最佳实践:并发安全、资源清理与高可用设计 Kubernetes 编程 / Operator 专题【左扬精讲】—— application-operator Reconcile 循环源码精讲:从 client-go Informer 到 workqueue 的全链路解剖 Kubernetes 编程 / Operator 专题【左扬精讲】—— 从零搭建一个 application-operator 新项目:脚手架、API 设计与基于原生 DeploymentStatus/ServiceStatus 的状态建模 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:生产级 Controller 实践:并发安全、资源清理与高可用设计 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析: Controller 调试与诊断工具:从日志分析到问题定位 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:DynamicClient 操作 CRD:无需代码生成的动态操作 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:控制器与 APIServer 完整交互流程:从 Watch 到缓存同步 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:错误处理与重试机制:WorkQueue 限速器详解 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Leader 选举机制:高可用控制器的必备技能 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Controller 开发模式完整实战 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:SharedInformerFactory 与等待缓存同步 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:从认证配置到 Deployment 操作 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:版本对应、架构组件与组件关系 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Informer 源码深度解析:从底层原理到实战应用 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Reflector 源码深度解析 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:ListWatcher 源码深度解析 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:Indexer 与 ThreadSafeStore 核心原理与源码深度剖析 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:DeltaFIFO 核心原理与源码深度剖析 Kubernetes 编程 / Operator 专题【左扬精讲】—— Client-go 源代码分析:workqueue 核心原理与实战 Kubernetes 编程 / Operator 专题【左扬精讲】—— runtime.Codec 资源编解码:serializer 与 codec 差异、编解码数据结构、codec 核心调用链路 Kubernetes 编程 / Operator 专题【左扬精讲】—— Scheme 资源注册机制全解 Kubernetes 编程 / Operator 专题【左扬精讲】—— Kubernetes 自定义资源的内部版本与外部版本:从源码看版本定义机制 Kubernetes 编程 / Operator 专题【左扬精讲】—— Kubernetes 1.36.1 核心 API 数据结构全解 Kubernetes 编程 / Operator 专题【左扬精讲】—— Kubernetes 构建过程 【AIOPS】一文读懂LLM【左扬精讲】:从诞生到普及,解锁大语言模型的核心密码 【AIOPS】AI Agent 专题【左扬精讲】核心功能篇:MCP-VictoriaMetrics Hooks 源码精讲:Hooks 可观测性的无侵入式实现 【AIOPS】AI Agent 专题【左扬精讲】核心功能篇:MCP-VictoriaMetrics Golang 配置解析源码精讲 ——SRE 自定义 Agent 核心技巧 【AIOPS】AI Agent 专题【左扬精讲】核心功能篇:MCP-VictoriaMetrics Golang 并发模型解析 ——SRE 应对高并发采集的调优思路 【AIOPS】AI Agent 专题【左扬精讲】基础架构篇:MCP-VictoriaMetrics Golang 源码整体架构拆解 ——SRE 必懂的核心模块与数据流 OpenTelemetry 开发实战【左扬精讲】—— 云原生可观测体系构建与分布式追踪二次开发 Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 7 —— 基于流量预测模型的智能弹性扩缩容 Operator 实战(AIOps 模型训练与智能扩容(下篇)—— 预测式弹性扩缩容 Operator 落地实现) Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 7 —— 基于流量预测模型的智能弹性扩缩容 Operator 实战(AIOps 模型训练与智能扩容(上篇)—— 时序预测模型构建与离线训练) Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 6 —— 基于运维专家知识库的智能故障诊断与排查 Operator 实战 Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 5 —— 基于大语言模型(LLM)的实时日志流智能监测 Operator 实现 Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 4 —— 基于 Operator 实现大模型私有化部署与管理 Kubernetes 编程 / Operator 专题【左扬精讲】—— Operator 开发实战项目 3(上篇)—— 面向 AI / 算力调度场景:GPU 竞价实例资源池统一调度管理 Operator 开发 Kubernetes编程 / Operator专题【左扬精讲】—— Operator 开发实战项目 2 —— 面向零售 / 电商潮汐流量难题:多云多集群数据中心级全链路弹性伸缩 DataCenter Scaler Operator 从 0 到 1 全链路开发 Kubernetes编程 / Operator专题【左扬精讲】—— 深入理解Kubebuilder注解:为什么Operator开发离不开这些特殊注释 Kubernetes编程 / Operator专题【左扬精讲】—— Operator 开发实战项目1 —— Applicaion Operator(通用应用生命周期管理 Operator 实战) Pod 镜像拉取失败?kubectl edit pods修改镜像地址的底层原理与实操 (该方法仅为临时应急方案,并非长期解决方案) Kubernetes编程/Operator专题精讲—— 理解控制器模式 —— 控制器模式的核心原理与实现逻辑(从原理到实践) 【AIOPS】AI Agent 专题【左扬精讲】模型微调实战:一站式平台 LLaMA-Factory 【AIOPS】AI Agent 专题【左扬精讲】基于 k8s+vLLM+Ray 分布式部署全指南:架构设计、资源调度与性能优化 【AIOPS】AI Agent专题【左扬精讲】非量化版DeepSeek分布式部署全指南:精度保障、显存规划与Ollama/vLLM选型 【AIOPS】AI Agent 专题【左扬精讲】零开发框架实现 ReAct Agent(Go SRE友好)
Rust 专题【左扬精讲】—— 变量、常量与标量数据类型
左扬 · 2026-06-24 · via 博客园 - 左扬

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

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

学习提醒

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

目录


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

1.1 单行注释

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

  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 约定用驼峰式(camelCase):my_variable,但标准库用下划线分隔(snake_case)
全大写+下划线(常量) 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::<bool>()); // 1
  println!("char: {} bytes", std::mem::size_of::<char>()); // 4
  println!("i32: {} bytes", std::mem::size_of::<i32>()); // 4
  println!("i64: {} bytes", std::mem::size_of::<i64>()); // 8
  println!("f64: {} bytes", std::mem::size_of::<f64>()); // 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::<i32>() // 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 的显式错误处理哲学

作者:Rust 学习者  |  发表于 2026 年  |  水平有限,欢迎指正