1. 先说点实在的:为什么“命名”这件事值得占掉一天的内容
我在团队里做Code Review的时候常说一句话:一个变量名写得好不好,比你的算法酷不酷更影响你在同事那里的口碑。算法看不懂可以问,命名一塌糊涂那就是纯粹的灾难。今天这篇Day2,我们专门聊常量与变量名的使用。
很多教程把这块当作“入门第一天随便讲讲就过了”的内容,但实际工作中你会发现,三五年经验的人照样在命名上踩坑。比如热搜里那几条东西:“表达式必须含有常量值”、“c# 变量名后加?”、“vue3 项目全局静态常量”、“哪组变量名称是合理的”——这些全是新手常搜的高频问题,而且答案并不像表面看起来那么简单。
这篇内容适合三类人:刚学编程、正在记笔记准备打基础的新手;从一门语言跳到另一门语言、被常量定义方式搞晕的转语言开发者;以及写RPA脚本、写数据分析脚本这类“非正统开发工种”、想把变量管理做得更规范的朋友。我尽量把原理和实操揉在一起讲,你看到的不只是“变量名怎么起”,还有“为什么这个报错会出现”“不同语言对常量的定义为什么不一样”这些背后的门道。
2. 常量与变量的本质区别:先从“变量是盒子”这个老比喻开始纠偏
2.1 变量的本质是给内存地址起个“人名”
很多教材喜欢说“变量是装数据的盒子”,这个比喻能帮新手起步,但很容易造成误解。真实的逻辑是这样的:你在代码里写int age = 25;,实际上是两件事——第一,向操作系统申请了一块能存放整数的内存空间;第二,把这块空间的地址跟名字age绑定。之后你写age,编译器知道你在说“地址0x7ffc1234那块内存里存的值”。
为什么要专门讲这个?因为只有理解了这层关系,你才能明白:
- 变量名本身不占多少存储,它只是编译器和人类之间的“翻译标签”;
- 变量名的核心功能是让代码可读,而不是让机器理解——机器只认地址;
- 所以变量名规范与否,影响的不是程序能不能跑,而是别人(以及三个月后的你自己)能不能看懂。
这个认知直接影响后面所有关于命名规范的讨论。
2.2 常量不是“不能变的变量”,它分编译期常量和运行期常量
新手最容易混淆的一句话是“常量就是值不能变的变量”。这个说法不准确。准确地说,常量分两类,它们的限制条件完全不同:
- 编译期常量:在程序编译阶段,它的值就已经确定并被“写死”进代码里。编译完成后,你甚至可以把存放它的那部分内存当成字面量来理解。典型代表是C语言里的
#define、C#里的const、Java里声明时就赋值的static final。 - 运行期常量:程序运行起来以后,给它赋值的时机可能是构造函数或者初始化代码,一旦赋值就不能再改。典型代表是C#里的
readonly、Java里在构造函数中赋值的final字段。
用生活类比的话:编译期常量像刻在石碑上的数字,工厂出厂时就铸死了;运行期常量像一把带密码锁的保险箱,你可以设置初始密码,但设置之后就不能改了。
这个区别是后面理解“表达式必须含有常量值”这个报错的关键,先记在这里。
2.3 为什么代码里必须存在常量?聊聊“魔法数字”的坏味道
你写代码的时候,肯定见过这类写法:
if (user.Status == 3) { // 做一些操作 }这个3是什么含义?订单已发货?账户已冻结?还是性别女?没人知道。这种在代码里直接出现的裸数字,行业里叫魔法数字(Magic Number),堪称可读性杀手。
改成常量之后就不一样了:
if (user.Status == UserStatus.Frozen) { // 做一些操作 }一眼就能看懂判断条件。这就是常量的第一个价值:给没有任何语义的字面量赋予有意义的名称。
第二个价值是维护性。假设这个3代表的业务含义在数据库里被改成了4,如果用魔法数字,你必须在整个项目里搜索所有出现3的地方,还得小心翼翼判断哪个3是状态、哪个3是别的逻辑;如果用了常量,只需要改一处定义。
所以常量不是编程的“限制”,反而是防止你手滑改错、防止后来人误读的安全网。
3. 变量命名的硬规则:哪些名字在语法层面就直接不合格
3.1 几乎所有语言都共通的四条红线
变量命名先别谈风格,先谈“能不能编译通过”。绝大部分主流语言(C、C++、Java、C#、JavaScript、Python、Go等)在这几条规则上是一致的:
- 只能由字母、数字、下划线(
_)和美元符号($)组成。注意,$在部分语言里合法(比如JavaScript/Java),但强烈不建议用在业务代码里,因为它在很多框架中有特殊用途。 - 不能以数字开头。
1variable可以直接判死刑,variable1则没问题。 - 不能是语言的关键字。比如你没法在Java里写
int class = 1;,因为class是关键字。 - 大小写敏感。
UserName和username是两个不同的变量,这一点在排错时特别容易坑人——眼睛扫过去一模一样,编译器却告诉你未定义。
这里有个小差异值得提:Python还允许变量名包含中文等Unicode字符,比如total_金额 = 100在语法角度是合法的,甚至某些中文编程场景下能提升可读性。但实际项目里我个人的建议是尽量别用,因为主流代码库、第三方库、IDE的自动补全对非ASCII字符的支持参差不齐,容易在跨平台协作时出幺蛾子。
3.2 命名风格之争:下划线、驼峰、帕斯卡到底该用哪个
语法过关之后,下一个问题就是风格。不同语言社区有不同的约定,这叫“社区惯例”,你不遵守它,代码能跑,但内行一眼就知道你是外来的:
| 风格 | 示例 | 主要使用场景 |
|---|---|---|
| snake_case(下划线命名法) | total_amount | Python、Ruby、Rust 的函数和变量 |
| camelCase(驼峰命名法) | totalAmount | JavaScript、TypeScript 的变量和函数、Java 的变量 |
| PascalCase(帕斯卡命名法) | TotalAmount | C# 和 Java 的类名、方法名(部分语言) |
| CONSTANT_CASE(全大写下划线) | MAX_RETRY_COUNT | 几乎所有语言的常量 |
| kebab-case(烤肉串命名法) | total-amount | HTML的>#define MAX_SIZE 100 const int WINDOW_WIDTH = 800;
但C的 C语言里要是写 4.2 C#的const与static readonly:热搜里“C#变量名后加?”是什么C#里的常量分两种,这直接对应前面说的编译期常量和运行期常量:
再说热搜词里那条“C#变量名后加?”。这个问号不是变量命名的一部分,它是可空值类型(Nullable)标记。 4.3 Java的static final:大多数情况下这就是“常量”Java没有 这里有个容易被忽略的细节: 4.4 Python和MATLAB:没有真常量的语言怎么约定Python官方文档明确说了:Python里没有不可变绑定的常量机制。PEP 8的建议是:模块级常量用全大写加下划线命名,比如 Python 3.8之后有了 MATLAB的情况类似,它没有强制的常量声明语法,常见做法有两种:一是全大写变量名当常量用,二是用一个函数文件返回固定值: 这也解释了热搜词里“matlab 转换为字符串常量”的用法——在MATLAB里把数字转成字符串通常用 4.5 Vue3项目的全局静态常量:撸一个推荐方案最后处理热搜词里的“vue3 项目全局静态常量”。在Vue3项目里,全局静态常量最朴素的方案就是建一个 组件里直接 5. 热搜里“表达式必须含有常量值”报错:完整排查链路5.1 报错到底在说什么这句报错是很多从C转C#或者从老教科书学C语言的人绕不过去的坎。常见触发代码长这样: 编译直接报错:“表达式必须含有常量值”。报错的位置指向 先别急着改代码,我们来拆解一下报错的含义:C#的 5.2 第一步排查:判断你到底需要编译期常量还是运行期常量遇到这个报错,先问自己一个问题:这个“常量”的值是在程序编译时就能确定,还是必须要等程序运行起来、读配置文件或算出来的那一刻才知道?
5.3 第二步排查:同样是C语言,为什么数组长度能用#define不能用const类似的坑在C语言里也有变体。看这段经典代码: 原因是:C语言的数组长度要求“整数常量表达式”, C++的情况完全不同:C++的 5.4 第三步排查:怎么快速确认当前编译器的“常量能力”如果你不确定当前的写法能不能当作编译期常量,有一个通用土办法:把它用在数组长度里试一下——因为数组长度是要求最严格的场景之一。在C#里,试试 这个“数组长度测试法”我几乎在每次技术答疑里都会教,简单直接又准确。 6. 从RPA到后端项目:命名实践怎么在真实场景里落地6.1 我在项目评审里最常挑的命名毛病做过多年代码评审,我总结出几类反复出现的命名问题,今天一起说了: 第一类是“类型后缀滥用”。有些老派开发喜欢把所有变量都带类型后缀,比如 第二类是“缩写过度”。 第三类是“中文拼音混搭”。这一条对国内开发者尤其常见。 6.2 RPA脚本里变量命名的特殊场景热搜词里的“rpa数据表文件变量”,我猜是写RPA流程(比如用影刀、UiPath这类工具)时,流程面板上自动生成了一堆 我的经验是给RPA变量名加一个“职责前缀”,例如:
这样在流程面板里按前缀查找,效率非常高。别嫌麻烦,一个几十步的RPA流程,到后期维护变量时你会感谢当初分类的自己。 6.3 命名自查清单:写完代码先过这五关我现在给团队定的验收标准很简单,变量名必须满足以下五条才算“合格”:
这套清单看着朴素,但配合Code Review执行下去,比什么高深的架构设计更容易快速提升代码质量。我见过最夸张的一次事故:一个结算模块里有人把两个订单金额变量起名为 写代码这事儿,语法决定你今晚能不能下班,命名决定你下个月还能不能看得懂自己写的代码。今天这篇聊完,建议你自己动手做个小练习:翻开最近写的一个程序,把所有变量名列个清单,挨个问自己“这个名字能不能让一个没看过代码的人猜到用途”。能想清楚这个问题,今天的Day2就真正过关了。 |