不知道下面的代码高亮了没有,我加了 ```c++,但是预览下的没高亮。应该是支持高亮的,我看其他的帖子里面有高亮的代码。
新做的一个项目,本来是用 Rust 写的,包管理很方便。但是组长说 Rust 招不到人,就让我用 C++ 重写。C++ 的话现在用的是 git submodules 和 cmake ,没那么爽。好在组长没说 C++ 的版本,应该能用上 C++20 。
本来是面向对象的命令式写法,但是网上冲浪太多了,经常看到函数式,早就想试试了,但其实自己面向对象也才懂一点点。最近想把测试写起来,因为自己的代码的其中两个 bug 让项目延期了几天,如果能写测试的话项目就不会在我这里卡住了。
如果是面向对象的测试的话,我看一般是定义一个接口,然后实现里面的纯虚函数,然后写 mock 类测试。但这样的话就需要为了测试去额外定义一个接口。我就想试试函数式,虽然我还不确定函数式能否让测试变得简单、没有额外负担。
下面的代码和测试无关,我只是想体验一下函数式。我想的是把那一大堆的 if 用 std::map 来代替,同时这个 std::map 在添加子命令的时候自动生成,这样子 main 函数的可读性就比原来好多了,行数也比较少。还有就是上面定义了变量,下面又传递给 SubCommand ,感觉复用度太低了,也许可以用一个结构体,然后和 SubCommand 组合一下。但是不知道具体怎么写。
有偿的话不知道 200 元行不行。
int main(int argc, char **argv) {
// parse command line
CLI::App cli;
string logLevel = "info";
cli.add_option("-l,--logLevel", logLevel, "log level")
->option_text("debug, info, warn, error")
->capture_default_str();
string logFile = "stdout";
cli.add_option("-f,--logFile", logFile, "log file")->capture_default_str();
bool version = false;
cli.add_flag("-v,--version", version, "show version")->capture_default_str();
auto &serveCli = *cli.add_subcommand("serve", "serve uart-manager service");
auto &readDataCli = *cli.add_subcommand("readData", "read data from uart-manager service");
uint32_t readDataPort;
readDataCli.add_option("-p,--port", readDataPort, "uart port")->required();
uint32_t messages = 1;
readDataCli.add_option("-m,--messages", messages, "stop after read ? messages")
->capture_default_str();
auto &setBaudRateCli = *cli.add_subcommand("setBaudRate", "set uart baud rate");
uint32_t setBaudRatePort;
setBaudRateCli.add_option("-p,--port", setBaudRatePort, "uart port")->required();
uint32_t setBaudRateBaudRate;
setBaudRateCli.add_option("-b,--baudRate", setBaudRateBaudRate, "uart baud rate")
->option_text("9600, 14400, 19200, 38400, 57600, 115200")
->required();
auto &writeDataCli = *cli.add_subcommand("writeData", "write data to uart-manager service");
vector<uint32_t> writeDataPorts;
writeDataCli.add_option("-p,--port", writeDataPorts, "uart port")->required();
string writeDataHex;
writeDataCli.add_option("-H,--hex", writeDataHex, "hex data");
string writeDataStr;
writeDataCli.add_option("-s,--str", writeDataStr, "string data");
auto &updateFpgaCli = *cli.add_subcommand("updateFpga", "update fpga");
string updateFpgaFile;
updateFpgaCli.add_option("-f,--file", updateFpgaFile, "fpga file")->required();
auto &getAutoResponseCli = *cli.add_subcommand("getAutoResponse", "get auto response");
uint32_t getAutoResponsePort;
getAutoResponseCli.add_option("-p,--port", getAutoResponsePort, "uart port")->required();
auto &clearAutoResponseCli = *cli.add_subcommand("clearAutoResponse", "clear auto response");
uint32_t clearAutoResponsePort;
clearAutoResponseCli.add_option("-p,--port", clearAutoResponsePort, "uart port")->required();
auto &addAutoResponseCli = *cli.add_subcommand("addAutoResponse", "add auto response");
uint32_t addAutoResponsePort;
addAutoResponseCli.add_option("-p,--port", addAutoResponsePort, "uart port")->required();
vector<string> addAutoResponseHex;
addAutoResponseCli.add_option("-H,--hex", addAutoResponseHex, "response hex data");
vector<string> addAutoResponseStr;
addAutoResponseCli.add_option("-s,--str", addAutoResponseStr, "response string data");
vector<string> addAutoResponseWhenContains;
addAutoResponseCli
.add_option("-w,--whenContains", addAutoResponseWhenContains,
"response str or hex data when contains str or hex data")
->required();
auto &getFpgaVersionCli = *cli.add_subcommand("getFpgaVersion", "get fpga version");
auto &set12vStatusCli = *cli.add_subcommand("set12vStatus", "set 12v of ports 1-48 status");
auto set12vStatusEnableFirst = true;
set12vStatusCli
.add_flag("-e,--enableFirst", set12vStatusEnableFirst, "enable first 12v, ports 1-24")
->capture_default_str();
auto set12vStatusEnableSecond = true;
set12vStatusCli
.add_flag("-s,--enableSecond", set12vStatusEnableSecond, "enable second 12v, ports 25-48")
->capture_default_str();
auto &get12vStatusCli = *cli.add_subcommand("get12vStatus", "get 12v of ports 1-48 status");
CLI11_PARSE(cli, argc, argv);
// version
if (version) {
printf("version: %s\n", VERSION);
return 0;
}
// log
initLog(logLevel, logFile);
// subcommands
if (serveCli) {
Manager().start();
} else if (readDataCli) {
SubCommand().readData(readDataPort, messages);
} else if (setBaudRateCli) {
SubCommand().setBaudRate(setBaudRatePort, setBaudRateBaudRate);
} else if (writeDataCli) {
SubCommand().writeData(writeDataPorts, writeDataHex, writeDataStr);
} else if (updateFpgaCli) {
SubCommand().updateFpga(updateFpgaFile);
} else if (getAutoResponseCli) {
SubCommand().getAutoResponse(getAutoResponsePort);
} else if (clearAutoResponseCli) {
SubCommand().clearAutoResponse(clearAutoResponsePort);
} else if (addAutoResponseCli) {
SubCommand().addAutoResponse(addAutoResponsePort, addAutoResponseHex, addAutoResponseStr,
addAutoResponseWhenContains);
} else if (getFpgaVersionCli) {
SubCommand().getFpgaVersion();
} else if (set12vStatusCli) {
SubCommand().set12vStatus(set12vStatusEnableFirst, set12vStatusEnableSecond);
} else if (get12vStatusCli) {
SubCommand().get12vStatus();
} else {
cout << cli.help() << endl;
}
return 0;
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.