我完全赞成做好前缀。
我认为(系统)匈牙利符号是造成前缀获得的大部分“坏名声”的原因。
这种表示法在强类型语言中基本上没有意义,例如在 C++ "lpsz" 中告诉你你的字符串是一个指向 nul 终止字符串的长指针,当:分段架构是古老的历史,C++ 字符串按照惯例是指向 nul 终止字符数组的指针,这并不是那么困难要知道“customerName”是一个字符串!
但是,我确实使用前缀来指定变量的用法(本质上是“Apps Hungarian”,尽管我更喜欢避免使用 Hungarian 这个术语,因为它与 System Hungarian 有不良和不公平的关联),这是一种非常方便的省时和减少错误的方法。
我用:
- 会员米
- c 用于常量/只读
- p 代表指针(pp 代表指向指针的指针)
- v 表示易失性
- s 用于静态
- i 用于索引和迭代器
- e 用于事件
在我希望明确类型的地方,我使用标准后缀(例如 List、ComboBox 等)。
这使程序员在看到/使用变量时就知道变量的用法。可以说最重要的情况是指针的“p”(因为用法从 var. 更改为 var-> 并且您必须更加小心指针 - NULL、指针算术等),但所有其他情况都非常方便。
例如,您可以在单个函数中以多种方式使用相同的变量名:(这里是 C++ 示例,但它同样适用于多种语言)
MyClass::MyClass(int numItems)
{
mNumItems = numItems;
for (int iItem = 0; iItem < mNumItems; iItem++)
{
Item *pItem = new Item();
itemList[iItem] = pItem;
}
}
你可以在这里看到:
- 成员和参数之间没有混淆
- 索引/迭代器和项目之间没有混淆
- 使用一组明确相关的变量(项目列表、指针和索引),避免“计数”、“索引”等通用(模糊)名称的许多缺陷。
- 与“itemIndex”和“itemPtr”等替代方法相比,前缀减少了输入(更短,并且更适合自动完成)
“iName”迭代器的另一个优点是我从不使用错误索引对数组进行索引,如果我将循环复制到另一个循环中,我不必重构循环索引变量之一。
比较这个不切实际的简单例子:
for (int i = 0; i < 100; i++)
for (int j = 0; j < 5; j++)
list[i].score += other[j].score;
(这很难阅读,并且经常导致在意为“j”的地方使用“i”)
与:
for (int iCompany = 0; iCompany < numCompanies; iCompany++)
for (int iUser = 0; iUser < numUsers; iUser++)
companyList[iCompany].score += userList[iUser].score;
(更具可读性,并且消除了对索引的所有混淆。在现代 IDE 中具有自动完成功能,这也可以快速轻松地键入)
下一个好处是代码 sn-ps 不需要任何上下文即可理解。我可以将两行代码复制到电子邮件或文档中,任何阅读该 sn-p 的人都可以分辨所有成员、常量、指针、索引等之间的区别。我不必添加“哦,并且是小心,因为 'data' 是指向指针的指针”,因为它被称为 'ppData'。
出于同样的原因,我不必为了理解它而将视线从一行代码上移开。我不必搜索代码来查找“数据”是本地、参数、成员还是常量。我不必将手移到鼠标上,因此我可以将指针悬停在“数据”上,然后等待工具提示(有时从未出现)弹出。因此,程序员可以显着更快地阅读和理解代码,因为他们不会浪费时间上下搜索或等待。
(如果您认为自己不会浪费时间上下搜索来解决问题,请查找一些您一年前编写但尚未查看的代码
自从。打开文件并向下跳转大约一半而不读取它。
在你不知道之前,看看你能从这一点读多远
某事是成员、参数或本地。现在跳到另一个随机
位置......这是我们单身时整天都在做的事情
单步执行别人的代码或试图了解如何
调用他们的函数)
“m”前缀还避免了(恕我直言)丑陋和冗长的“this->”符号,以及它所保证的不一致(即使你很小心,你通常最终也会混合使用 'this-> data' 和 'data' 在同一个类中,因为没有强制名称的拼写一致)。
'this' 表示法旨在解决 歧义 - 但是为什么有人会故意编写可能有歧义的代码呢?歧义迟早会导致错误。在某些语言中,“this”不能用于静态成员,因此您必须在编码风格中引入“特殊情况”。我更喜欢有一个适用于任何地方的单一简单编码规则 - 明确、明确和一致。
最后一个主要好处是 Intellisense 和自动完成功能。尝试在 Windows 窗体上使用 Intellisense 来查找事件 - 您必须滚动浏览数百个您永远不需要调用来查找事件的神秘基类方法。但是,如果每个事件都有一个“e”前缀,它们将自动列在“e”下的组中。因此,前缀可以对智能感知列表中的成员、常量、事件等进行分组,从而更快、更容易地找到所需的名称。 (通常,一个方法可能有大约 20-50 个值(locals、params、members、consts、events)可以在其范围内访问。但是在输入前缀之后(我现在想使用索引,所以我输入 'i. ..'),我只看到了 2-5 个自动完成选项。将“额外输入”的人归因于前缀和有意义的名称大大减少了搜索空间并显着加快了开发速度)
我是一个懒惰的程序员,上面的约定为我节省了很多工作。我可以更快地编写代码,而且我犯的错误也少得多,因为我知道应该如何使用每个变量。
反对意见
那么,有什么缺点呢?反对前缀的典型论据是:
“前缀方案是坏的/邪恶的”。我同意“m_lpsz”及其同类产品经过深思熟虑并且完全没用。这就是为什么我建议使用设计良好的符号来支持您的要求,而不是复制不适合您的上下文的内容。 (为工作使用正确的工具)。
“如果我改变了某些东西的用法,我必须重命名它”。是的,你当然知道,这就是重构的全部意义所在,以及为什么 IDE 有重构工具可以快速、轻松地完成这项工作。即使没有前缀,更改变量的用法几乎肯定意味着应该更改其名称。
“前缀让我很困惑”。就像每个工具一样,直到你学会如何使用它。一旦你的大脑习惯了命名模式,它就会自动过滤掉信息,你不会真的介意前缀的存在。但是你必须在你真正变得“流利”之前牢固地使用这样的方案一两个星期。这就是很多人看到旧代码并开始怀疑他们是如何管理没有一个好的前缀方案的时候。
“我可以看看代码来解决这个问题”。是的,但是当答案就在您的注意力已经集中的位置时,您无需浪费时间查看代码的其他地方或记住其中的每一个小细节。
(部分)可以通过等待工具提示在我的变量上弹出来找到该信息。是的。在支持的情况下,对于某些类型的前缀,当您的代码干净地编译时,等待之后,您可以通读描述并找到前缀将立即传达的信息。我觉得前缀是一种更简单、更可靠、更高效的方法。
“打字更多”。真的吗?还要一整个角色?或者是 - 使用 IDE 自动完成工具,它通常会减少输入,因为每个前缀字符都会显着缩小搜索空间。按“e”,您班级中的三个事件会以智能方式弹出。按“c”,列出五个常量。
“我可以使用this-> 代替m”。嗯,是的,你可以。但这只是一个更丑陋、更冗长的前缀!只有它会带来更大的风险(尤其是在团队中),因为对于编译器来说它是可选,因此它的使用经常是不一致的。另一方面,m 简短、清晰、明确且不是可选的,因此使用它更难出错。