单字符常量比文字常量好吗?


127

最近,我遇到了一个类,该类几乎将每个单个字符都提供为常量。从COMMA到的一切BRACKET_OPEN。想知道这是否必要;我读了一篇“文章”,它暗示将单字符文字转换为常量可能会有所帮助。所以,我对此表示怀疑。

使用常量的主要吸引力在于,当需要更改时,它们可以最小化维护。但是,什么时候开始使用不同于','的符号来表示逗号呢?

我看到使用常量而不是文字的唯一原因是使代码更具可读性。但是city + CharacterClass.COMMA + state(例如)真的比city + ',' + state吗?

对我而言,弊大于利,主要是因为您介绍了另一类和另一项内容。而且我相信尽可能减少代码。因此,我想知道这里的普遍共识是什么。



33
嗯...对于不同的区域可能有用,也许吗?例如,某些语言使用guillements(尖括号«»)作为引号,而不是英语的标准"(或更好看的)。除此之外,它听起来像是一组魔法人物。假设两个实例CharacterClass名为englishCharsfrenchChars,它可能是englishChars.LEFT_QUOTE可能,而frenchChars.LEFT_QUOTE可能是«
贾斯汀时间

4
逗号上有很多不同的变体:en.wikipedia.org/wiki/Comma#Comma_variants-也许这不是一个愚蠢的主意,尤其是如果您的源代码可以编码为utf-8。
亚伦·霍尔

21
就您而言,这就像调用变量“数字”一样。您的常数应称为DELIMITER。否则应为CITY_STATE =“ {0},{1}”
the_lotus

13
您链接的那篇文章非常糟糕。绝对不要将常量丢进这样的桶中。将它们放在具有上下文的类上:本质上,具有常量的类提供了使用常量的上下文。例如,Java的File.separator。该类告诉您分隔符的类型。有一个名为ConstsConstants没有提供上下文的类,会使常量更难正确使用。

Answers:


184

重言式

很清楚,如果您读到该问题的第一句话,则该问题与 消除魔术数字之 类的适当用途无关,充其量只是关于可怕的无意识愚蠢的一致性。这个答案要解决的是

常识告诉你,const char UPPER_CASE_A = 'A';或者const char A = 'A'不添加任何东西,但维护和复杂系统。const char STATUS_CODE.ARRIVED = 'A'是不同的情况。

常量应该表示在运行时不可变的事物,但将来可能需要在编译时进行修改。什么时候可以const char A =正确地等于A

如果您public static final char COLON = ':'在Java代码中看到,请找出编写该代码的人并破坏他们的键盘。如果您的表述COLON永远发生变化,:您将面临一场维修噩梦。

混淆:

当某人将其更改为COLON = '-'因为在哪里使用它-而在任何地方都需要它时会发生什么?您是否要编写单元测试,基本上assertThat(':' == COLON)针对每个const参考说一下,以确保它们不会被更改?只是让某人在更改测试时修复测试?

如果有人真的认为这public static final String EMPTY_STRING = "";是有用和有益的,那么您只需限定他们的知识,然后在其他所有事情上都可以忽略它们。

具有可命名版本的每个可打印字符都表明,无论是谁做的,都没有资格在无人监督的情况下编写代码。

凝聚:

它也人为地降低了内聚力,因为它使事物远离使用它们并与之相关的事物。

在计算机编程中,内聚性是指模块的各个元素所属的程度。因此,内聚度量了给定模块内功能之间的关系强度。例如,在高度内聚的系统中,功能密切相关。

耦合:

它还将许多不相关的类耦合在一起,因为它们最终都引用与它们的工作没有真正关系的文件。

紧密耦合是一组类之间高度依赖的情况。当班级承担太多职责时,或者当一个问题分散到多个班级而不是拥有自己的班级时,就会出现这种情况。

如果您使用一个更好的名称,那么DELIMITER = ','您仍然会遇到同样的问题,因为名称是通用名称,不包含任何语义。重新分配值仅比搜索和替换文字无助于进行影响分析','。因为有些代码使用它并需要,和其他代码使用但;现在需要什么?仍然必须手动查看每次使用并进行更改。

在野外:

我最近重构了一个1,000,000+ LOC18岁的应用程序。它有类似的事情public static final COMMA = SPACE + "," + SPACE;。这绝对比仅" , "在需要的地方内联更好。

如果您想提高可读性,则需要学习将IDE配置为显示whitespace字符以查看字符或其他内容,这是将熵引入系统的极其懒惰的原因。

它还,COMMA多个包和类中的多个单词拼写错误多次定义了该单词。与所有变体的引用在代码中混合在一起。尝试修复某些问题而又不会破坏完全无关的内容,这简直就是一场噩梦。

同样的,字母,有多个UPPER_CASE_AAUPPER_AA_UPPER,大部分的时间都是相等A ,但在某些情况下没有。对于几乎每个字符,但不是所有字符。

而且从编辑历史来看,似乎没有一个在18年中曾被编辑或更改过,因为现在应该很明显的原因是它将破坏太多无法追踪的内容,因此您有了新的变数指向同一事物的名称,由于相同的原因而永远无法更改。

在任何理智的现实中,您都不能说这种做法没有做任何事情,而是从最大熵开始的。

我将所有这些混乱都进行了重构,并内插了所有的重言式,新的大学员工的工作效率更高,因为他们不必通过这些const引用实际指向的多个间接层级进行搜寻,因为它们在命名方面并不可靠与它们包含的内容。


112
也许您应该添加一个反例:const char DELIMITER = ':'实际上会有用。
Bergi 2016年

115
我会提出几个EMPTY_STRING有益的论点。(1)与查找的所有用法EMPTY_STRING相比,我可以更轻松地找到文件中的所有用法""。(2)当我看到EMPTY_STRING我知道该死的时候,一定要确保开发人员希望该字符串为空,并且以后提供该字符串不是错误的编辑或占位符。现在,您声称通过我提出此论点,您​​可以限定我的知识,并永远永远忽略我。那么,您如何鉴定我的知识呢?您是否打算永远忽略我的建议?两种方式我都没问题。
埃里克·利珀特

39
@immibis:我们可以停止将这些事情视为对管理变更有用。他们是常数。他们没有改变。认为它们在人类搜索和理解代码语义的上下文中很有用。知道的东西是一个键-值对分隔符被比知道它是一个冒号更加有用; 那是关于程序所关注的语义域而不是其语法的事实。
埃里克·利珀特

15
@EricLippert:我有点看到别人在这里谁指出,一个唯一保证的点const提供的是,它不会在运行时改变(编译后),但我不同意你说的语义const是比将其用作变更管理工具更为重要。就是说,我当然可以想象到const EARLIEST_OS_SUPPORTED,它不仅在语义上是一致的,而且随着程序的发展和旧文件的删除将随着时间的推移而变化。
罗伯特·哈维

16
@DanielJour:所以这是第三个论点EMPTY_STRING;精心设计的IDE将浮出水面,这些工具使我可以象征性地而非语法上地对待该实体。将其概括为第四个参数:位于IDE下方的代码分析工具库可允许在符号级别对代码正确性进行高级编程分析。希望使用比40年前实际编写的工具更高级的工具的开发人员,只需对其习惯进行一些改动即可获得高级工具的收益。
埃里克·利珀特

145

使用常量的主要吸引力在于,当需要更改时,它们可以最小化维护。

绝对不。这根本不是使用常量的原因,因为常量在定义上不会改变。如果一个常数发生了变化,那么它不是一个常数,对吗?

使用常量的吸引力与变更管理没有任何关系,与使程序适合于人们编写,理解和维护的程序无关。如果我想知道程序中使用冒号作为URL分隔符的所有地方,那么如果我有定义常量URLSeparator的准则,就可以很容易地知道这一点,并且如果必须使用grep可以完全不知道这一点。:并获得代码中:用于指示基类,?:运算符或其他任何内容的每个位置。

我完全不同意其他答复,这些答复指出这是浪费时间。命名常量程序增加了含义,人和机器都可以使用这些语义来更深入地理解程序并更有效地维护程序。

这里的窍门不是避免常量,而是用它们的语义属性而不是句法属性来命名它们。该常数用于什么?Comma除非程序的业务领域是印刷术,英语分析等,否则请不要调用它。调用它ListSeparator或类似的东西,以使事物的语义清晰。


42
虽然我同意您在此所说的精神,但您的第二/第三句话并不是真的正确。常量可以在文件的版本之间改变。实际上,我编写的大多数程序都有一个名为的常量,如MY_VER,它包含程序的当前版本号,然后可以在程序的其余部分中使用它,而不是像“ 5.03.427.0038”这样的魔术字符串。正如您所说,附加的好处是它提供了语义信息。
Monty Harder

50
公平地说,常量的要点是它在初始化后在运行时不会更改,而不是在编译之间不会更改。从编译器的角度来看,关键是编译器可以假设程序无法对其进行修改;在重新编译时是否允许程序员对其进行修改不会改变其常量性。在某些情况下,软件可能会通过取消const volatile T*指向预定地址的指针来从硬件获取只读值。虽然程序无法更改,但硬件可以更改。
贾斯汀时间

6
@MontyHarder:好点。我的观点是基于这样一个事实,即我通常使用区分常数(必须永远不变)和可以分配一次的变量(可以随版本而变化,运行到运行等)之间进行区分的语言。常量和变量是不同的东西;一个保持不变,一个随着时间变化。
埃里克·利珀特

7
@SteveCox:我同意;C / C ++表征“ const”的方式很奇怪并且用途有限。我想要的常量属性是它们的值不会更改,不是在某些函数中而不是在其他函数中我不受其限制。
埃里克·利珀特

15
“这根本不是使用常量的原因,因为常量在定义上不会更改。如果常量曾经更改,那么它不是常量,是吗?” 在编译时更改常量(显然不是在运行时)是完全正常的。这就是为什么首先要使它们成为带有明显标签的“事物”的原因。当然,OP的常数都是垃圾,但想到像const VERSION='3.1.2'const KEYSIZE=1024或什么的。
AnoE '16

61

不,那是愚蠢的。

什么是不是一定是哑巴拉之类的东西转化为本土化的原因命名的标签。例如,成千上万的分隔符在美国(1,000,000)一个逗号,而不是在其他区域设置一个逗号。将其放入命名标签(带有适当的非逗号名称)中,可使程序员忽略/抽象这些细节。

但是,因为“魔术字符串不好”而使常数不变只是货物的培养。


8
本地化通常比仅字符串常量更复杂。例如,某些语言要在所有列表项之间使用列表定界符,而其他一些语言则要在最后一项之前排除定界符。因此,通常不需要本地化常量,而是本地化规则
弗拉德(Vlad)2016年

19
实际上,千位定界符并不一定是其他语言环境(中国/日本)中的千位定界符。固定位数后甚至没有设置(印度)。哦,取决于它是1000分隔符还是1000000分隔符(墨西哥),可能会有不同的分隔符。但这比在某些语言环境中不使用ASCII数字0-9(Farsi)要小得多。ux.stackexchange.com/questions/23667/…–
彼得

1
@Vlad本地化要比这复杂得多,但是,千位分隔符是人们公认的众所周知的示例。

这取决于本地化策略...您是否更改程序中的所有常量以进行翻译?还是应该从文件(或其他数据存储)中读取值,以使其有效地成为运行时变量?
圣保罗Ebermann

那么,将其作为一个常量根本没有用。该程序将需要针对区域设置进行重新编译,这是很糟糕的做法。它们应该是从定义文件加载的变量,并根据需要进行查找。并非我不同意这一点(我对答案投了赞成票),但我会在此问题上持更严格的立场。

29

有一些字符可能是模棱两可的,或用于几种不同的目的。例如,我们使用'-'连字符,减号或破折号。您可以单独命名为:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '-';
static const wchar_t EM_DASH = '-';

以后,您可以选择将代码重新定义为:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '\u2122';
static const wchar_t EM_DASH = '\u2014';

这可能就是为什么要考虑某些单个字符定义常量的原因。 但是,以这种方式模棱两可的字符数很少。最多看来,您只会为那些人这么做。我还认为,您可以等到实际需要区分歧义字符后再以这种方式分解代码。

由于印刷约定可能会因语言和地区而异,因此最好从翻译表中加载此类歧义的标点符号。


对我来说,这是可能会创建字符常量的唯一有效原因
FP

2
使用-作为一个破折号是非常容易引起误解......这是很短的,在大多数字体。(它甚至比破折号还短。)
PaŭloEbermann

好的,不是最好的例子。我从strings而不是wchar_ts 开始,并使用"--"破折号的标准手稿约定。但是最初的示例使用的是单个字符,因此我转而保持对问题的关注。有些人输入-破折号,尤其是在使用固定间距字体时。
阿德里安·麦卡锡

1
@PaŭloEbermann不,传统上,破折号是字体的'm'字符的宽度,而破折号是'n'字符的宽度。
迪兹利,2016年

@Dizzley是的,连字符宽度<n-width <m-width。
圣保罗Ebermann

22

常数必须增加含义。

将COMMA定义为逗号不会增加含义,因为我们知道逗号是逗号。相反,我们破坏了含义,因为现在COMMA可能实际上不再是逗号。

如果您出于目的使用逗号,并且想要使用命名常量,请以目的命名。例:

  • city + CharacterClass.COMMA + state =不好
  • city + CITY_STATE_DELIMITER + state =好

使用功能进行格式化

我个人更喜欢FormatCityState(city, state)并且不关心该函数的主体看起来如何,只要它简短且通过测试用例即可。


1
啊,但是逗号并不总是相同的逗号。我可以定义COMMA ='\ u0559'或'\ u060C'等(请参见Unicode),甚至以后将其转换为变量并从配置文件中读取。这样,它仍将具有相同的含义,但只是具有不同的值。那个怎么样。
李斯特先生,2016年

2
@MrLister:YAGNI。如果您有此需求:太好了!您有一个好的解决方案。但是,如果您不这样做,请-不要使代码混乱,因为也许您有一天可能会这样做。同样,根据我的经验,如果您尝试在代码库中引入没有任何功能的抽象,那么人们就不是一致的。因此,即使您确实确实出于使用一些其他代码点的定义而定义COMMA的目的,在一个大小和年龄都足够使选择很重要的程序中,您仍可能会发现该常量并未在应有的所有地方使用曾经(相反,可能也被不适当地使用)。
Eamon Nerbonne'7

17

恒定COMMA优于','","相当容易揭穿的想法。当然,在某些情况下它是有意义的,例如final String QUOTE = "\"";,在没有所有斜杠的情况下,make大大节省了可读性,但是除非有诸如此类的语言控制字符,\ '而且"我还没有发现它们非常有用。

使用final String COMMA = ","不仅形式不好,而且很危险!当有人想要将分隔符从更改为时","";"他们可能会将常量文件更改为,COMMA = ";"因为这样做对他们来说更快,并且可以正常工作。除了,您知道,现在使用COMMA的所有其他东西也都是分号,包括发送给外部使用者的东西。因此它通过了所有测试(因为所有编组和解组代码也都使用COMMA),但外部测试将失败。

给他们起有用的名字是有用的。是的,有时多个常量将具有相同的内容但名称不同。例如final String LIST_SEPARATOR = ","

因此,您的问题是“单个char常量比文字常量好吗”,而答案肯定是不,不是。但是比这两个都更好的是一个狭窄范围的变量名,它明确说明了它的用途。当然,您将在这些额外的引用上花费一些额外的字节(假设它们可能不会在您身上编译出来),但是在长期维护中,这是应用程序大部分成本的来源,值得花时间。


取决于目标平台,如何有条件地将DISP_APOSTROPHE定义为ASCII 0x27或Unicode单右引号字符(这是一个更适合印刷形式的撇号)?
超级猫

3
实际上,QUOTE示例也证明这也是一个坏主意,因为您将其分配给通常/通常称为的, DOUBLE QUOTEQUOTE暗示将SINGLE_QUOTE其更正确地称为APOSTROPHE

3
@JarrodRoberson我个人认为引号不是单引号-但这是消除歧义的另一个好理由!
corsiKa '16

2
我不喜欢该QUOTE示例,"Hello, my name is " + QUOTE + "My Name" + QUOTE这是因为它是一个琐碎的示例,但是看起来仍然很糟糕。哦,当然,可以使用替换令牌代替串联,这也"Hello, my name is %sMy Name%s".format(QUOTE, QUOTE)可能更糟。但是,嘿,让我们尝试索引令牌吧"Hello, my name is {0}My Name{0}".format(QUOTE),不是更好。任何带有引号的非平凡字符串都会更糟。
VLAZ '16

2
@corsiKa-我将使用转义的实际报价。如果我错过了转义,我使用的IDE将立即抱怨。代码很可能也不会编译。这很容易发现。做错错误有多容易,"My name is" + QUOTE + "My Name" + QUOTE实际上我在写上面的评论三遍时就犯了同样的错误。你能发现吗?如果需要一点时间,它是is之后的缺失空间。您格式化字符串吗?在这种情况下,要替换的带有多个标记的字符串将变得更加糟糕。我该如何使用它以使其更具可读性?
VLAZ '16

3

我已经完成了编写词法分析器和解析器的工作,并使用整数常量表示终端。为简单起见,单字符终端碰巧以ASCII码作为其数字值,但该代码本来可以完全是别的东西。因此,我有一个T_COMMA,它被分配了ASCII码“'”作为其常量值。但是,非终端也有常量,这些常量被分配为ASCII集以上的整数。通过查看诸如yacc或bison之类的解析器生成器,或使用这些工具编写的解析器,我得到的印象是,基本上每个人都是这样做的。

因此,尽管和其他所有人一样,我认为为明确表达目的而使用常量而不是整个代码中的文字来定义常量是没有意义的,但我确实认为在某些情况下(解析器),您可能会遇到混乱的代码您所描述的常量。注意,在解析器的情况下,常量不仅仅代表字符常量。他们表示可能只是实体碰巧是字符文字。

我可以想到一些更孤立的情况,在这些情况下,使用常量而不是相应的文字可能会有意义。例如,您可以将NEWLINE定义为unix框上的文字'\ n',但是如果您在Windows或mac框上,则将其定义为'\ r \ n'或'\ n \ r'。解析表示表格数据的文件也是如此;您可以定义FIELDSEPARATOR和RECORDSEPARATOR常量。在这些情况下,您实际上是在定义一个常量,以表示可以发挥某种功能的字符。不过,如果您是新手程序员,也许您会将字段分隔符命名为COMMA,而不是意识到您应该将其命名为FIELDSEPARATOR,那么到您意识到的时候,该代码将投入生产,而您将继续下一个工作。项目,

最后,您描述的做法在某些情况下可能是有意义的,在这种情况下,您编写代码来处理以特定字符编码(例如iso-8859-1)编码的数据,但希望以后会更改编码。当然,在这种情况下,使用本地化或编码和解码库来处理它会更有意义,但是如果由于某种原因您不能使用此类库来为您处理编码问题,则只使用常量必须在单个文件中重新定义,而不是在源代码中乱七八糟的硬编码文字,这可能是一种方法。

至于您链接到的文章:我认为它不会为用常量替换字符文字提供理由。我认为它试图说明一种使用接口将常量提取到代码库其他部分的方法。用于说明此问题的示例常量选择得很糟糕,但我认为它们没有任何关系。


2
我认为它试图说明一种使用接口将常量提取到代码库其他部分的方法。这是更糟糕的反模式,并且紧密耦合且内聚性很低,也没有充分的理由这样做。

3

除了这里所有好的答案之外,我想补充一点,好的编程是要提供适当的抽象,您可以自己或其他人来构建这些抽象,而不必一遍又一遍地重复相同的代码。

好的抽象一方面使代码易于使用,另一方面又易于维护。

我完全同意DELIMITER=':',本质上来说,它本身是一个糟糕的抽象,并且仅比COLON=':'(因为后者完全贫穷)好。

涉及字符串和分隔符的良好抽象方法是,在告诉您分隔符是什么之前,首先也是最重要的是将一个或多个单独的内容项打包到字符串中,并从打包的字符串中解压缩它们。这样的抽象将被捆绑为一个概念,在大多数语言中都是一个类。例如,为了使它的使用实际上是自我记录的,您可以搜索使用该类的所有位置,并对每种使用某种抽象的情况下程序员对打包字符串格式的意图有信心。

一旦提供了这种抽象,它将很容易使用,而不必咨询DELIMITERor 的值COLON,并且更改实现细节通常将限于该实现。简而言之,这些常量实际上应该是隐藏在适当抽象中的实现细节。

使用常量的主要吸引力在于,当需要更改时,它们可以最小化维护。

好的抽象通常由几种相关功能组成,可以更好地减少维护。首先,他们清楚地将提供者与消费者分开。其次,它们隐藏了实现细节,而是提供直接有用的功能。第三,它们在何时何地使用它们的高级文档。


2

我曾经看到有效使用这样的常量的一次是匹配现有的API或文档。我看到过诸如之类的符号,COMMA因为特定的软件直接与解析器相连,该解析器用作COMMA抽象语法树中的标记。我还看到它曾经与正式规范匹配。在正式的规范中,您有时会看到类似的符号,COMMA而不是','因为它们希望尽可能清晰。

在这两种情况下,使用诸如like的命名符号COMMA有助于使本来不相交的产品具有凝聚力。该值通常会超过过于冗长的符号的代价。


2

观察到您正在尝试列出清单。

因此,将其重构为: String makeList(String[] items)

换句话说,要考虑逻辑而不是数据
语言在表示列表的方式上可能有所不同,但是逗号始终是逗号(这是重言式)。因此,如果更改语言,则更改逗号字符将无济于事-但这会有所帮助。


0

如果这是您的开发人员作为应用程序的一部分编写的类,那么几乎可以肯定这是一个坏主意。正如其他人已经指出的那样,定义常量是有意义的,例如可以SEPARATOR = ','在其中更改值的常量,而常量仍然有意义,但更不用说常量,其名称仅描述其值。

但是,至少有两种情况是有意义的:声明其名称准确描述其内容的常量,并且在不适当更改常量名称的情况下不能更改值:

  • 数学或物理常数,例如PI = 3.14159。在这里,常量的作用是充当助记符,因为符号名PI比其表示的值短得多并且可读性强。
  • 解析器中的符号或键盘上的键的详尽列表。拥有包含大多数或所有Unicode字符的常量列表甚至可能是有意义的,这就是您的情况所在。诸如此类的某些字符A是显而易见的,并且易于识别。但是,您可以轻松分辨АA分开吗?第一个是西里尔字母А而后者则是拉丁文字母A。它们是不同的字母,由不同的Unicode代码点表示,即使在图形上它们几乎相同。我宁愿有常数CYRILLIC_CAPITAL_ALATIN_CAPITAL_A在我的代码中,有两个看起来几乎完全相同的字符。当然,如果您只知道使用不包含西里尔字母的ASCII字符,那么这毫无意义。同样:我每天都使用拉丁字母,因此,如果我正在编写需要中文字符的程序,我可能会更喜欢使用常量而不是插入我不理解的字符。对于每天使用汉字的人来说,汉字可能是显而易见的,但拉丁字母可能更易于表示为命名常量。因此,如您所见,它取决于上下文。尽管如此,库可能仍包含所有字符的符号常量,因为作者无法事先知道该库将如何使用以及哪些字符可能需要常量以提高特定应用程序的可读性。

但是,这种情况通常是由系统类或专用库处理的,除非您正在从事一些非常特殊的项目,否则在应用程序开发人员编写的代码中这种情况很少发生。


-1

也许。

单字符常量相对难以区分。因此,很容易错过添加句号而不是逗号这一事实。

city + '.' + state

而这是一个相对困难的错误

city + Const.PERIOD + state

根据您的国际化和全球化环境,ASCII撇号和Windows-1252打开和关闭撇号(或ASCII双引号和Windows-1252打开和关闭双引号)之间的差异可能很大,并且众所周知很难看起来在代码。

现在,大概是,如果错误地放置了句号而不是逗号是一个重要的功能问题,那么您将拥有一个自动测试,可以找到错字。如果您的软件正在生成CSV文件,那么我希望您的测试套件会很快发现您在城市和州之间有一段时期。如果您的软件应该为具有各种国际化配置的客户端运行,则假定您的测试套件将在每种环境中运行,并且如果您打算使用单引号,那么如果您使用Microsoft公开报价,则该套件将开始运行。

我可以想象一个项目,选择更详细的代码可以避免这些问题,这更有意义,特别是当您有没有全面测试套件的较旧代码,即使我可能不会这样编写代码时一个绿色领域的发展项目。并且为每个标点符号添加一个常量,而不只是为您的特定应用中可能存在问题的标点添加一个常量,可能会造成严重的后果。


2
当某个白痴的变化Const.PERIOD等于时会发生什么~?重命名命名字符是没有道理的,它只是增加了维护和复杂性,而现代编程环境中并没有这些。您是否打算编写一套基本上说的单元测试assert(Const.PERIOD == '.')

3
@JarrodRoberson-肯定会的。但是,如果有人添加了看起来几乎完全像逗号而不是实际逗号的Unicode常量,您将遇到同样的麻烦。就像我说的那样,这不是我在新建项目中要做的那种事情。但是,如果您的旧代码库带有参差不齐的测试套件,并且您在逗号/句号或撇号/ Microsoft憎恶撇号问题上跳了几次,则创建一些常量并告诉人们使用它们可能是一种合理的方法无需花费一年的时间编写测试代码就可以使代码更好。
贾斯汀·凯夫

3
您的旧示例很糟糕,我刚刚重构了18年以上的1,000,000+ LOC代码库。它多次定义了每个这样的可打印字符,甚至具有不同的冲突名称。很多次COMMA,实际上是设置了命名的事物= SPACE + "," + SPACE。是的,一些白痴有一个SPACE常数。我将它们全部重构了,代码更加清晰易读,大学录用人员更容易追踪和修复它们,而无需进行6级间接查找来确定实际设置的内容。

-1

单字符常量比文字常量好吗?

这里有很多混用。让我看看是否可以将它们分开。

常量提供:

  • 语义学
  • 在开发过程中进行更改
  • 间接的

简化为单个字符名称只会影响语义。名称应作为注释并在上下文中清晰可见。它应该表达含义,而不是价值。如果可以用一个字符完成所有操作。如果不能,请不要。

在开发过程中,文字和常量都可以更改。这就是出现幻数问题的原因。字符串也可以是幻数。

如果存在语义,并且由于两者都是常量,那么常量是否具有比文字更多的价值将归因于间接。

间接可以解决任何问题,而不仅仅是间接。

间接可以解决幻数问题,因为它使您可以在一个地方决定一个想法的值。从语义上说,要使该名称有价值,必须使该名称明确。名称应与想法有关,而不是价值。

间接可以过分。有些人更喜欢搜索和替换文字以进行更改。只要42显然是生命的意义并且不与42(钼的原子序数)混合在一起就可以了。

此外,您可以像使用单个字母一样做出有用的区分,这很大程度上取决于上下文。但是我不会养成习惯。


1
语义是关键。如果和“ A”的语义比简单地成为“ A”多,那么将相同的语义绑定到相同的“引用”是值得的。是否为常数都没有关系。我完全同意。
oopexpert

-1

作为多数派观点的哲学矛盾,我必须指出,我们当中有些人很欣赏朴素的19世纪法国农民程序员和

记得他单调,永恒的清醒,他对一切事物的愚蠢明智的看法,对无私主义的巨大满足仅仅是因为它们是真实的。“把一切都弄乱了!” 特恩布尔对自己喊道,“如果他在庇护中,外面就不会有人。”

GK切斯特顿,《球与十字架》

欣赏真理没有错,陈述真理也没有错,尤其是在与计算机交谈时。

如果您对计算机撒谎,它将帮助您

佩里·法拉尔(Perry Farrar)-马里兰州日耳曼敦(来自More Programming Pearls)


但是,在大多数情况下,我同意那些认为它愚蠢的人。我还太年轻,还没学会编程FORTRAN,但是我听说您可以重新定义'A' = 'Q'并提出各种精彩的密码。您没有这样做。

除了之前提出的i18n问题(不是重新定义字形“ COMMA”,而是真正地重新定义DECIMAL_POINT的字形)。构建法国的胡萝卜引号或英国的单引号来传达对人类的意义在于事物,而那些引号实际上应该是变量,而不是常量。常数将是AMERICAN_COMMA := ','comma := AMERICAN_COMMA

而且,如果我使用构建器模式来构建SQL查询,我宁愿看到

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(" ( ")
 .append(val_1)
 .append(",")
 .append(val_2)
 .append(" ); ")

比什么都重要,但是如果您要添加常量,它将是

INSERT_VALUES_START = " ( "
INSERT_VALUES_END = " ) "
INSERT_VALUES_SEPARATOR = " , "
QUERY_TERMINATOR = ";"

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(INSERT_VALUES_START)
 .append(val_1)
 .append(INSERT_VALUES_SEPARATOR)
 .append(val_2)
 .append(INSERT_VALUES_END)
 .append(QUERY_TERMINATOR)

但是,如果您曾经看过其他任何程序(或键入),则可能会注意到一些有趣的怪癖。并非所有人都是出色的打字员。我们中的许多人都迟到了编程,或者是使用苏维埃键盘(按键在您的键盘上输入的)长大的,我们喜欢剪切和粘贴单个字母,而不是尝试在键盘上查找它们和/或依靠自动完成功能。

什么都不会自动为您完成字符串,因此,如果我可以通过按'con',alt空格,下,下,下,下,输入,输入报价并按'con',alt空格,下,向下,进入。我可能会那样做。


关于字符串文字,要记住的另一件事是它们的编译方式。至少在Delphi中(这是我一直迷恋于堆栈的唯一语言),您最终会将文字直接弹出到每个函数的堆栈中。因此,大量的文字=大量的函数开销;为了解决这个问题,在function_A中的“,”与在function_B中的“,”不是相同的内存。要解决这个问题,可以横向构建和链接一个“资源字符串”-这就是他们做i18n事情的方式(杀死两只鸟,只有一个灌木丛。)在Python中,所有的字符串文字都是对象,使用起来似乎很不错utils.constants.COMMA.join(["some","happy","array","strings"]),但是对于在此页面上重复一遍的问题来说,这并不是一个好主意。


-4

但是,什么时候开始使用不同于','的符号来表示逗号呢?

对于本地化。

在说英语的国家/地区,将小数部分的全部和小数部分分开的符号是“。”,我们称其为“小数点”。在许多其他国家/地区,该符号为“,”,在本地语言中通常称为“逗号”的等价物。同样,在讲英语的国家/地区中,如果使用“,”来分隔大量的三位数字(例如1,000,000表示一百万),则使用逗号作为小数点的国家/地区使用点(1.000.000)。

因此,如果要进行全球化,则有必要使DECIMAL_POINT和COMMA常量。


2
但是,COMMA和DECIMAL_POINT并不是实体的正确名称(这可能就是为什么您被否决的原因)。
凯尔·斯特兰德

您需要编译特定的本地化版本。文字常量不适合这种情况;该用例将要求定义文件并在其中进行查找(可能涉及常量,但是查找常量,而不是常量字符)。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.