自动化样式检查#
为 C++ 和 Python 强制执行 SUMO 代码样式的最简单方法是启用 pre-commit 检查。
C++ 代码#
我们力求代码兼容广泛的 C++11 编译器,并针对 macOS 和 Linux 上的 gcc 与 clang 以及 Windows 上的 Visual Studio 2015 - 2022 测试每一个提交/拉取请求。对于 C++ 代码,我们使用 AStyle 来保持整个项目的缩进和其他空白用法一致。为了使您的代码与原始 SUMO 代码外观一致,请使用以下 AStyle 调用(或者在提交前执行 tools/build_config/checkStyle.py --fix
astyle --style=java --unpad-paren --pad-header --pad-oper --add-brackets --indent-switches --align-pointer=type -n <FILE_NAME>
尽管如此,您还应牢记以下几点(Google C++ 风格指南 也值得一读):
模板#
请为您的文件使用以下模板:
空白#
- 永远不要使用 制表符。缩进始终使用 4 个空格。在 Visual Studio 中,可以在 工具/选项/文本编辑器/所有语言/制表符 中禁用 制表符。
类名#
- 所有类名必须以大写字母开头
- 类名的首字母大写应指示其模块(NBEdge -> Net Build 模块,MSChargingStation -> Micro Simulation 模块)
- 如果类名由多个单词组成,每个单词必须以大写字母开头(Micro simulation charging station -> MSChargingStation)
- 请不要随意引入新的命名空间
变量名#
- 方法内部使用的变量应使用“驼峰式命名法”命名,例如 "currentCarVelocity"
- 成员变量应额外带有前缀 "my",例如 "myMaximumVehicleVelocity"
- 尽量不要缩写变量名(使用 myMaximumVehicleVelocity 而不是 myMVV)
- 给变量命名应描述其在上下文中的用途
- 不要将变量用于不同的目的
枚举#
- 所有枚举名必须以大写字母开头,如果其名称由多个单词组成,每个单词必须以大写字母开头
- 每个定义必须使用大写字母编写(SumoXMLTag { SUMO_TAG_EDGE, SUMO_TAG_LANE, ... })
编码#
在 cpp 和 h 文件中仅使用纯 ASCII 字符(0x20 - 0x7E)。如果需要传递扩展字符信息,请改用 TeX 或 HTML 表示法。
#include 语句#
- 不要使用反斜杠 (\)! 仅使用斜杠 (/)
- 不要使用绝对路径!;像 #include "/home/daniel/mylibs/include_me.h" 这样的语句在其他地方永远无法工作! 使用相对路径并告诉编译器在哪里可以找到其他库。如果您在这方面遇到问题,请告诉我们,我们会编写进一步的文档!
- 通常我们首先提及标准库的包含(如 #include <vector>),然后是 SUMO 使用的库的包含(FOX / Xerces),最后是我们自己的头文件
- 对于不在同一目录中的文件,首选使用尖括号 ("<" 和 ">"),而引号通常用于同一目录中的文件。
"using namespace ..."-语句#
- 尽可能避免使用,尤其是在 .h 文件中不要使用 "using namespace ..."-语句! 包含的库可能会尝试使用不同的实现——谁知道呢?在您的 .h 文件中使用 "using namespace ..."-语句可能会导致意外行为。
Throw 声明#
- 我们不使用 throw 声明,参见:http://www.gotw.ca/publications/mill22.htm(感谢 Björn Hendriks);我们将随后删除现有的声明。
对象处理#
- 如果您正在实现的结构有一个 id,则从
Named派生对象 (<SUMO_HOME>/src/utils/common/Named.h)。此类支持std::string getID()方法。 - 如果您想将某些内容存储在从字符串 id 映射到对象实例的映射中,请使用
NamedObjectCont(<SUMO_HOME>/src/utils/common/NamedObjectCont.h)。
整数类型#
- 尽可能使用简单的 int。sumo 代码中可能有很多地方依赖于它至少有 32 位这一事实,因此您也可以这样做。
- 尽可能避免使用无符号整数。在调用 Xerces-C 和 GL 函数或使用 std::string::npos 时有时无法避免,但请尽量将其限制在这些情况下。
- 如果需要至少 64 位,请使用 long long int。
条件语句#
- 不要使用冗余的条件检查。示例:if (myCondition) 而不是 if (myCondition == true)
循环#
- 尽可能使用 C++ 11 范围循环语法。示例:for (element& it : myContainer) 而不是 for (container::iterator it = myContainer.begin(); it != myContainer.end(); it++)。尽管如此,在遍历列表/向量时,尽量显式命名元素类型,而不是使用 "auto"。
Python 代码#
我们力求遵守 PEP 8 风格指南 并使用 autopep8 和 flake8 进行检查。如果您安装了这两个模块,可以运行 tools/build_config/checkStyle.py <FILENAME> 来检查并修复一些错误。我们运行这两个工具时不使用任何特殊选项,除了将行长限制为 120。
请记住,如果(且仅当)文件应是可执行文件时(即不是要被其他人导入的模块),请使其可执行。Windows 用户请遵循此 方法。可执行文件还应在第一行包含所谓的 shebang:
!#/usr/bin/env python
如果您的脚本需要 Python 3,请在其中注明 python3。
Python2 / Python3 兼容性#
我们的主要开发侧重于 Python 3.7 及更高版本,但我们力求 Python 2 兼容性。编写或编辑脚本时,请牢记以下几点:
- 将 print 用作函数 (
from __future__ import print_function) - 使用 items 代替 iteritems,这在 Python 2.7 下将返回列表,在 Python 3 下返回迭代器 (
for item in dict.items()) - 使用 values 代替 itervalues,这在 Python 2.7 下将返回列表,在 Python 3 下返回迭代器 (
for val in dict.values()) - 使用 // 代替 / 进行整数除法,因为在 Python 3 下 / 将执行浮点除法 (
4/3 = 1.3333333) - 使用 / 的浮点除法可以通过 (
from __future__ import division) 包含在 Python 2 中 - 在遍历未排序的列表或迭代器时,Python 2 和 Python 3 的工作顺序不同。因此,在编写例如 xml 文件时,在迭代前添加显式的 sorted (
for item in sorted(list)) - 使用 argparse 库代替 optparse(已弃用)。大多数函数的使用保持不变,只是名称有所不同。更多信息请查看 https://docs.python.org/3/library/argparse.html
- 如果您想为 Python 2 和 Python 3 使用不同的代码(这可能是必要的,因为并非所有库都同时支持这两个版本),您可以使用带有 PY3 布尔值的简单 if else 语句,该布尔值由 (
PY3 = sys.version_info > (3,)) 定义 - 在 Python 3 中,凡是在使用二进制数据的地方使用字节类型,在以前使用 unicode 字符串的地方使用字符串类型。这可以通过使用 PY3 布尔值的 if else 语句来实现。有关字节和字符串上可能的不同方法的列表,请参见 https://docs.python.org/3/howto/pyporting.html#text-versus-binary-data
有关 Python 3 兼容性可能的错误来源和困难的更多信息,请参见 http://python3porting.com/ 和 https://docs.python.org/3/howto/pyporting.html
模板#
请为您的文件使用以下模板:
行尾和关键字替换#
我们对以下文件类型强制执行特殊的行尾(覆盖 git 的 core.autocrlf 设置),使用 <SUMO_HOME>/.gitattributes:
- LF 用于
- 源文件 (".h", ".cpp", ".py", ...),
- 测试文件 (".xml", ".prog", ".complex", ".dfrouter", ".duarouter", ".jtrrouter", ".netconvert", ".sumo", ".meso", ...)
- CRLF 仅用于 Windows 的文件 (".bat", ".props", ".vcxproj", ".filters", ...)
Git 没有等同于 svn:keywords 的属性,因此我们不再使用 $Id$ 关键字。
