我有一个变量,我正在使用它像一个常量(它永远不会改变)。我不能将它声明为常量,因为值会在运行时添加。
您是否会将变量名称大写以帮助您了解数据的含义?
或者你不因为这会违反惯例并使事情更加混乱?
更大的问题:
您是否遵循惯例,即使该场景不是典型的惯例,但足够接近以至于它可以帮助您个人理解事物?
答案 0 :(得分:10)
如果它能帮助你(以及其他所有人)在六个月之后理解你的代码,那就去做吧。如果不这样做,不要。这真的很简单。
就个人而言,我会将其资本化。这是Java中的约定,其中常量由于其面向对象的特性而总是在运行时分配。我知道如果我不小心分配给它,我会更加自如地知道,下次我扫描那段代码时,我肯定会注意到。
答案 1 :(得分:9)
我不认为我的个人在这里必须是最重要的 - 如果我已经编写了代码,那么如果需要的话,我已经比其他任何人更好地回溯它了。因此,我首先提出的是“其他任何人” - 现在或未来的队友需要像我一样彻底地理解代码(理想情况)。
此外,强制性的代码审查作为向代码库提交任何东西的先决条件(一种优秀的做法,以及我现在雇主的不懈规则),如果我让我的注意力滑落,我很可能会被提起来(它确实发生了 - 这就是为什么我喜欢那些强制性的代码审查,适用于我自己以及其他所有人! - 。)。
“在启动时只设置一次变量”是一个特殊的情况,可能值得添加到团队的指导方针 - 将其视为“更接近常量而不是变量”可能很有意义,但是只有在整个代码库中使用相同的规则/指南时才有用。如果规则不存在,我会检查是否有关于添加规则的共识;否则,我不会为了个人口味而违反指导原则......这是“无形编程”和“代码库的团队所有权”的根源,这是我为燃烧热情服务的两个原则。
顺便说一句,如果我在编码指南方面是一个单人团队(虽然这不是一个最佳情况,但它发生了),我认为我可以毫不费力地获得自己一致认可的“一次性”在启动时“变量作为命名约定的常量! - )。但是对于一个更大的团队来说,这是更多的工作,而且它可以采取任何一种方式。答案 2 :(得分:1)
我将它命名为变量,我更喜欢保持命名非常一致。 正如Rob已经建议的那样,readonly(至少在C#中可用)。 或者没有制定者的财产。
答案 3 :(得分:1)
封装它。
#include <iostream>
class ParamFoo
{
public:
static void initializeAtStartup(double x);
static double getFoo();
private:
static double foo_;
};
double ParamFoo::foo_;
void ParamFoo::initializeAtStartup(double x)
{
foo_ = x;
}
double ParamFoo::getFoo()
{
return foo_;
}
int main(void)
{
ParamFoo::initializeAtStartup(0.4);
std::cout << ParamFoo::getFoo() << std::endl;
}
这应该很清楚,除了在应用程序启动时,你不应该在其他地方设置这个值。如果您想要添加保护,可以添加一些私有防护boolean
变量,以便在多次调用initializeAtStartup
时抛出异常。
答案 4 :(得分:1)
我的直接印象是,只要业务规则不变,您“在运行时设置,然后永不改变”的内容就是常量。此外,您应该使用mutators / accessors,因为使用ALL CAPS几乎不能保证“constness”。
public class BadClass
{
public static final double PI = 3.1;
// PI is very constant. Not according to the business roles modeled by my
// application, but by nature. I don't have a problem making this publicly
// accessible--except that [Math] already does, with much better precision)
public static /*final*/ int FOO = null;
// FOO is constant only by convention. I cannot even enforce its "constness".
// Making it public means that my enemies (overtime, for example) can change
// the value (late night programming), without telling me.
}
相反,
public class BetterClass
{
public static final double PI = 3.1;
private /*final*/ Integer foo = null;
public int getFoo() {
return this.foo.intValue();
}
public void setFoo(int value) {
// The business rules say that foo can be set only once.
// If the business rules change, we can remove this condition
// without breaking old code.
if ( null == this.foo ) {
this.foo = value;
} else {
throw new IllegalStateException("Foo can be set only once.");
}
}
}
如果你总是使用mutator设置值,即使在[BetterClass]本身内,你也知道foo的“constness”不会被违反。当然,如果有人要直接设置foo的值(我需要在凌晨2点之前退出工作!),仍然没有保证。但是在代码审查中应该指出类似的东西。
所以我的建议是将foo视为普通的成员变量 - 对于几乎为const的东西,不需要特殊的命名约定。
但是,使用mutators / accessors,甚至是私有变量。这些通常非常快,您可以在其中强制执行业务规则。这应该是你的惯例。
(如果您正在为嵌入式医疗设备编写代码,请假装您从未看过此帖子。)
答案 5 :(得分:0)
是否可以将其标记为只读?惯例并不重要。
答案 6 :(得分:0)
你是否遵循惯例即使 场景不是典型的 惯例,但足够接近它 个人而言,可能对你有帮助 了解事情?
遵循惯例,当场景不典型时可能会混淆或减慢其他人(或者甚至是你,过一段时间。)我会避免给变量设置一些它不具备的东西。
此外,您有这种非典型情况的事实可能表明可能会遵循其他一些更典型的范例。但是,我没有任何关于替代方案的直接建议。
答案 7 :(得分:0)
我会把它变成大写的(因为它从设计的角度看它比变量更常量)并在它周围加上一条注释,说明它对应用程序的独特性。
答案 8 :(得分:0)
FWIW我自己的惯例是使用#define
和枚举的全部大写。对于const
变量,我要么不使用特定的约定,要么在我这样做的时候用名称前缀'k
'('konstant' - 不是'c
'已经结束了用于'count'或'char'之类的东西。
我发现我喜欢'k
'约定,并且可能会更频繁地使用它,甚至可能将它用于枚举,为可怕的预处理器宏保留尖叫的全大写标识符。< / p>
答案 9 :(得分:0)
首先,请遵循您项目的编码标准。你应该为其他阅读代码的人编码,而不是自己。您的个人偏好不应优先于项目范围的规则和惯例等。
如果没有项目编码标准,您应该遵循您所处理语言的“最佳实践”。
在Java中,最佳实践是您应该使用驼峰大小写标识符声明伪常量。这就是Sun Java编码标准所说的,而这正是绝大多数专业Java开发人员所使用的。
在C和C ++中,(经典)约定是all-caps用于定义为预处理器符号的常量。因此,由于这不是预处理器符号,因此您应该使用您的编码标准所说的适合变量的任何内容。
伪常量不应该改变的事实不会阻止某人修改代码,使其实际上无意或有意地改变。如果您使用/滥用使标识符看起来的编码约定像真正的constaint一样,您将成为问题的一部分:
实际上,处理伪常量的更好方法是封装它。在Java中,您将其声明为私有成员并提供getter和setter。设置器应该做一些事情来防止伪常量在第一次设置后被更改。任何体面的Java JIT编译器都会内联一个简单的getter,所以这不应该影响运行时性能。
答案 10 :(得分:0)
惯例就是惯例。他们在那里帮助代码可以理解。如果他们没有选择得太糟糕,并且如果他们一贯地应用,他们通常会这样做。最后一点可能是关于它们的最重要的事情:它们应该始终如一地应用。
有一件事阻止某些约定使代码更具可读性,即使它们被一致地应用 - 至少对于新来者和在代码库之间切换的人 - 是它们与其他约定冲突的时候。在C和C ++中,我知道有关在ALL_CAPS中使用名称的两个常见约定:
为预处理器保留它们;我的偏好是预处理器标识符是特殊的:它们不遵守通常的范围规则并且防止与它们发生冲突很重要
将它们用于常量(宏和枚举器)。
除了不熟悉之外,还有两个问题,如果你将它们用于实际上可变的逻辑上不变的东西:
它们不适用于语言期望持续表达的地方(如数组大小)
我的经验告诉我,维护会使他们现在变得更加不变。
答案 11 :(得分:0)
使用单个私有静态字段创建包装类。创建一个initField(..)和一个getField(..)静态方法。如果静态字段不为null,则initField抛出/断言/否则出错。 (对于基元,您可能必须使用基元和布尔值来跟踪初始化。)
在java中,我更喜欢将这些类型的变量作为系统属性传递。然后静态类可以执行以下操作:
public final int MY_INT = Integer.getInteger("a.property.name");
您也可以使用属性文件(请参阅java.util.Properties)而不是使用-D来指定它。然后你得到:
public class Foo {
public static final int MY_INT;
static {
Properties p = new Properties();
try{
p.load( new FileInputStream("app.props"):
} catch(IOException e) {
//SWALLOW or RETHROW AS ERROR
}
MY_INT=Integer.parseInt( p.getProperty("my.int","17") ); //17 is default if you swallo IOException
}
...
}
答案 12 :(得分:0)
提供错误信息通常不是最佳做法。
隐含地声称某事物是一个常数,当它只是当前没有改变时,却发出了错误的信息。
答案 13 :(得分:0)
一个问题是:什么样的变量?
在静态变量的情况下,由于缺少更好的术语而在我称之为“启动时间”之后没有改变,我使用ALL_CAPS ...同样的事情用于全局变量(如果语言支持他们都在......)
通信语义实际上是命名约定的点,并且看到ALL_CAPS明确指出,a)我不会写入它b)我可以缓存它(例如,对局部变量,或者在AS3中甚至是实例变量)有道理,因为静态访问非常慢)...
它是否是一个“真正常数”并不重要......这更像是一个实现细节,应该隐藏起来(可靠!信息隐藏是好的,重要的,但重要的是,信息这是共享的,可以信任!)...它可以真正交换...例如,我经常开始构建应用程序与一些硬编码配置,包含一些静态常量...后来,我决定我不希望这是硬编码,而是来自一些配置文件,所以我加载它,并在启动过程中,我初始化所有伪常量...实际应用程序仍然将它们视为常量,因为启动后,这就是什么这些价值观......这对我来说似乎完全有效......
在实例级别,我不是100%肯定,如果我遇到过一个案例,我可以非常肯定,某些领域永远不会改变......通常,这会使课程不灵活...
除此之外,你通常可以声明只读属性,有编译时错误,这也是一件好事......
答案 14 :(得分:0)
我不确定这是否合法用你选择的语言,但在C ++中,这可以用于你的目的:
#include <iostream>
int main()
{
int i = 0;
std::cin >> i;
const int CONST = i;
std::cout << CONST; //displays i
system("PAUSE");
return 0;
}
我不确定这是否是道德的事情,但这确实解决了你的问题(除非你真的需要你的记忆)。
答案 15 :(得分:0)
就像其他任何东西一样 - 范围和上下文需要知道某些东西是不变的。所以 - 没有办法满足每个人。
按照您选择的语言使用的风格 - 80%的时间,足够清晰。替代方案是一个高度过度的命名系统,它牺牲了生产力以实现理想的技术正确性(如果你能实现它,很少有人会真正应对它。)