那是一个非常模糊的标题,但我想不出一种更好的措词。但是,作为一个示例,请考虑游戏中角色的前进方向。先使用字符串然后再执行类似操作,这是一种错误if(character.direction == "left")
。在我看来,它为愚蠢的错误留了太多的空间,例如不小心使用Left
或l
或而不是left
。我的怀疑正确吗?如果是这样,实现这种目标的首选方式是什么?
bash
。
那是一个非常模糊的标题,但我想不出一种更好的措词。但是,作为一个示例,请考虑游戏中角色的前进方向。先使用字符串然后再执行类似操作,这是一种错误if(character.direction == "left")
。在我看来,它为愚蠢的错误留了太多的空间,例如不小心使用Left
或l
或而不是left
。我的怀疑正确吗?如果是这样,实现这种目标的首选方式是什么?
bash
。
Answers:
在代码中使用文字字符串(或幻数)是一种可怕的做法。
枚举很好,或者至少使用常量(枚举当然只是一个或多个相关常量的包装类型)。
const string LEFT = "left"
if (someThing == LEFT) { doStuff(); }
这个简单的开关有很多优点,我什至都不知道从哪里开始解释它们(至少没有更多的咖啡)。阅读魔术数字,这是完全相同的概念,只适用于数字值而不是字符串值。
这是一个快速的参考,我敢肯定还有更多:https : //stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad
简短的答案:是的,除了存储和访问文本字符序列以外,字符串不是任何任务的理想选择,即使抽象的基础位是字符串,将它们引用为变量或常量也有好处。
答案很长:大多数语言提供的类型都更接近您的问题所在,即使不是,您也可以使用某些方法将其定义left
为不同于right
(等)的实体。通过使用将其转换为字符串"left"
仅会丧失该语言和IDE的有用功能(例如错误检查)。即使你必须使用
left = "left";
或类似的东西,当您在代码中引用字符串时,它具有使用字符串的优势。例如,
if (player.direction == Left)
会被检测为编译时错误(最好的情况,java等),或者由值得将其位视为错误的所有IDE标记为错误(最坏的情况,基本等)。
此外,使用“ left
作为可引用实体” 的概念将帮助您适应您决定要使用方向类型的任何方向。通过使用"left"
,方向致力于成为一个String
。如果您为该类型找到或创建了更好的抽象,则需要遍历整个代码体,以更改每个的实例"left"
。如果详细说明了类型,则常量或变量将不需要任何更改。
您真正想要的类型特定于您的域。您打算如何处理您的代码left
?也许您需要镜像朝左或向前移动的纹理或精灵的x轴;如果是这样,您可能希望left
使用具有反映该行为的属性或方法的right
对象,而该对象具有相反的非镜像结果。你可以这样做的逻辑在代表精灵或纹理,在这种情况下,你又将会使用遭受对象"left"
,而不是left
出于上述原因。
在Java(以及我可能还不知道的其他语言)中,enum
是一个很好的选择,因为在Java中,enum
它final class
与有限的实例集一样有用。您可以根据需要定义行为,也可以切换到一个开放类,而在声明的文件之外没有任何麻烦enum
,但是许多语言将an enum
作为基本类型或要求使用特殊语法。这会使enum
与之无关的代码暴露在外,以后可能需要更正。enum
在考虑使用该选项之前,请确保您了解语言的概念。
您没有指定语言,但是要给出一个通用的答案,您应该在实际需要文本时使用字符串,而不是代表某些东西。例如,您给出的示例在生产软件中根本不可接受。
每种语言都有各种基本数据类型,您应该使用最适合该任务的一种。要使用您的示例,您可以使用数字常量来表示不同的状态。因此left的值为零,right的值为1。除了您提到的原因之外,数字值所占用的空间(内存)更少,并且比较数字总是比比较多个字符串快。
根据建议,如果您的语言允许,请使用枚举。在您的特定示例中,这显然是更好的选择。
if (uppercase(foo) == "LEFT")
只需使用适合您情况的数据类型即可。
使用该string
类型作为基础的内部/应用程序内部通信本质上不是问题。实际上,有时最好使用字符串:如果您有一个公共API,则可能需要使该API传入和传出的值是人类可读的。它使使用您的API的人们更容易学习和调试。
您的代码的真正问题在于重复该值。
不要这样做:
if (direction == 'left') {
goLeft();
}
如果您在其中某些条件条件或“ left”的其他用法中输入了错误,则可能由于键入错误而无法有效地在代码库范围内进行搜索!
取而代之的是,针对枚举或常量进行编码-取决于使用您所使用的语言支持哪种数据类型。
这意味着LEFT
应在您的应用程序中分配一次且仅分配一次。并且,其余代码应利用这些枚举或常量:
const string LEFT = "left";
if (direction == LEFT) {
goLeft();
}
如果您愿意的话,这也使您以后可以更轻松地更改用于方向的数据类型。
这是不好的做法吗?
也许是的,但是这取决于究竟你在做什么,也对编程语言所使用。
在您的示例中,我们可以推断出方向可能会包含一小部分且永远固定的值。在这种情况下,使用字符串没有优势,但有一定的劣势。对于此示例:
enum
如果您的编程语言支持,则最好使用类型。但是,如果一组值是可动态修改的,或者需要随着时间的推移而变化,答案可能会有所不同。在大多数语言中,更改enum
类型(例如,添加或删除值)需要完全重新编译。(例如,在Java中删除枚举值将破坏二进制兼容性。)同样,命名整数常量也是如此。
在这种情况下,可能需要其他解决方案,并且使用字符串是一种选择。(并且,如果场景需要具有动态扩展的固定核心,则可以将字符串文字和命名常量结合在一起。)
如果您使用Java实现,character.direction == "left"
则出于另一个原因,这是不好的做法。您不应该使用==
比较字符串,因为它是在测试对象身份而不是字符串相等性。(如果可以保证"left"
字符串的所有实例都已被内插,则可以使用,但是这需要对整个应用程序进行分析。)
String
表示方向将使进行更改所涉及的工作量几乎接近零差异。一个更明智的做法是假设方向的数量不会改变,并承认,你将有很多工作要做,无论哪种方式,如果游戏规则改变,从而从根本上。
根据建议,您应该使用枚举。但是,仅使用Enum替代Strigns是不够的恕我直言。在您的特定示例中,玩家速度实际上应该是物理上的矢量:
class Vector {
final double x;
final double y;
}
然后,此向量应用于更新每个刻度的玩家位置。
然后,您可以将其与枚举结合使用以提高可读性:
enum Direction {
UP(new Vector(0, 1)),
RIGHT(new Vector(1, 0)),
DOWN(new Vector(0, -1)),
LEFT(new Vector(-1, 0));
private Vector direction;
Direction(Vector v) {
this.direction = v;
}
public Vector getVector() { return this.direction; }
}