else if

一看到else if都不陌生,都用过,这不就是C的一种语法吗?

首先需要纠正的是, else if不是C的语法,C的语法,只有 if else,例如:

if (a){

//do something  — A

}else{

//do something   — B

}

这是C的经典的语法,这也是它的唯一语法。但是它有一些扩展。

当作用A和作用域B中的内容只有一条语句时,可以缩写大括号,例如:

if (a)

func1();

else

func2();

说到这,大概我们就知道else if的由来,

if (a == 1){

func1();

}

else{

if(a== 2){

func2();

}else{

func3();

}

}

由于else中的语法,其实可以认为是一个TRUNK, 因此也可以认为一条语法,因此可以缩略大括号,于是就有了else if的写法。

同样我们可以写出,else while, else switch的写法,只不过那些写法过于难看,我们通常都会加上大括号,因此就没有流行

这样的写法。

else if后需深思一些东西

我们理解else if背后原理,你会发现,当我们缩略了大括号之后,写成else if更简洁,而如果不缩略,当我们else if几次之后,

你会发现,层级会非常的深,也就是压栈会非常的深,教我们C++的老师,再讲递归函数的时候,就说过尽量不要写递归函数,

原因就在压栈,是非常耗性能的。

所以,我们不要被else if表面的语法迷惑,它实际层级是非常深的,我以前工作遇到一个非常奇葩的问题,就是else if编译报错的问题

就是由于代码的扩展性差的原因,有一个函数,写了大量的else if语句,后续一旦新的需求,就在函数最后,补上一个else if, 我记不清楚,

具体多少个else if, 但是达到一定数量之后,编译期,就报错了,你们可以自行验证一下,反正1000个以内,编译期会直接报错的。最后的

解决办法也很奇葩,就是在尾部else中调用了一个新的函数,又开始重头if, else if。

虽然很好笑,但是确实解决了这个问题,通过欺骗编译器,让它不报错,至于编译会为啥会报错,清楚else if的背后原理的你们,应该已经知道

原因呢。

那我们使用else if应该注意些什么呢?

首先else if隐藏了栈的深度,即便是老程序猿, 都会忽略这个问题,我们在使用else if,尽量不要超过5个,其实有的公司要求函数的栈的深度

(专业词忘记了,具体数字应该也不是5哈,但是不超过10)。

但是,问题来了,我现在就是超过10个,甚至20个了,有没有其他的替代方法呢?

替代方案

switch

switch语法都不陌生,如果是一些整形判断,我们可以使用switch语法,这个大家都知道,也没啥可说的。

静态map

我们举一个例子吧,找一个Fimora中的一个函数,说明一下:

void FFCefview::onInvokeMethodNotify(int browserId, int frameId, const QString& msg, const QVariantList& arguments)
{
LOG_INFO(“%s”, msg.toStdString().c_str());
QJsonParseError jsonParseError;
QJsonDocument jsonDocument = QJsonDocument::fromJson(msg.toUtf8(), &jsonParseError);
if (jsonParseError.error == QJsonParseError::NoError)
{
QJsonObject jsonObj = jsonDocument.object();
QString method = jsonObj.value(“method”).toString();
if (method == “login_wsid”)
{
#ifndef FILMORA_FOR_MIAOYING
emit sigWebCallBackMethed(WSID_LOGIN_FINISHED, QVariant());
#else
QString token = jsonObj.value(“token”).toString();
QString uid = QString::number(jsonObj.value(“uid”).toVariant().toLongLong());
emit sigGetWSIDTokenFinished(token, uid);
#endif

}
else if (method == “login_by_h5”)
{
#ifndef FILMORA_FOR_MIAOYING
emit sigWebCallBackMethed(WSID_LOGIN_BYH5, QVariant());
#else
QString token = jsonObj.value(“token”).toString();
QString uid = QString::number(jsonObj.value(“uid”).toVariant().toLongLong());
emit sigGetWSIDTokenFinished(token, uid);
#endif
}
else if (msg == “user_sign_out”)
{
emit sigWebCallBackMethed(WSID_lOGIN_OUT, QVariant());
}
else if (method == “token_update”)
{
QString token = jsonObj.value(“token”).toString();
emit sigWebCallBackMethed(TOKENUPDATA_FINISHED, token);//TODO
}
else if (method == “plan_open_browser”)
{
QString url = jsonObj.value(“url”).toString();
emit sigWebCallBackMethed(PLAN_OPENBROWSER,url); //内嵌购买页弹刷新授权,没有内嵌购买页了
}
else if (method == “user_update”)
{
emit sigWebCallBackMethed(USER_UPDATE,QVariant()); //刷新授权 TODO
}
else if (method == “open_browser”)
{
QString url = jsonObj.value(“url”).toString();
emit sigOpenBowser(url);
}
else if (method == “plan_continue_use”)
{
emit sigWebCallBackMethed(PLAN_CONTINUE_USE, QVariant());
}
else if (method == “plan_login_tips”)
{
emit sigWebCallBackMethed(PLAN_LOGIN_TIPS, QVariant());
}
else if (method == “plan_register”)
{
emit sigWebCallBackMethed(PLAN_REGEIST, QVariant());
}
else if (method == “plan_login”)
{
emit sigWebCallBackMethed(PLAN_LOGIN, QVariant());
}
else if (method == “plan_activate”)
{
emit sigWebCallBackMethed(PLAN_ACTIVATE, QVariant());
}
else if (method == “plan_refresh”)
{
emit sigWebCallBackMethed(PLAN_REFRESH, QVariant());
}
else if (method == “open_terms”)
{
QString url = jsonObj.value(“url”).toString();
emit sigOpenBowser(url);
}
else if (method == “find_password”)
{
emit sigWebCallBackMethed(PLAN_FINDPASSWORD, QVariant());
}
else if (method == “register”)
{
emit sigWebCallBackMethed(REGEIST, QVariant());
}
else if (method == “close_box”)
{
emit sigWebCallBackMethed(CLOSE_BOX, QVariant());
}
else if (method == “open_success”)
{
emit sigWebCallBackMethed(OPEN_SUCCESS, QVariant());
}
emit sigWebCallBack(msg);
}
}

可以看出,这个代码中else if写了很多哈,表面上只有3层,实际上,是很多层的,且不说如果命中的最后一个else 需要平台的判断很多字符串比较。压栈就非常的恼火,他们如果替换成静态map的写法呢?

static std::map<std::string,  std::function<void()>> mapper = {

{“open_terms”, func1},

{“register”, func2},

….

};

这里,key为std::string, value写成std::function, 聪明的人是活学活用,你可以相办法替换哈,比如成员函数指针声明,比如每一个else中调用的是同一个函数,只是参数不一样时,你的value就可以是一个参数包,又比如,后面是不停在new 一个对象,你可以选择,传入构造器。这种写法,最大的好处时,是层级非常的浅,另外一个好处,判断次数也少了。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。