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 一个对象,你可以选择,传入构造器。这种写法,最大的好处时,是层级非常的浅,另外一个好处,判断次数也少了。
评论(0)