一次移植代码时关于For循环的发现

  欢迎参与讨论,转载请注明出处。

前言

  今日使用Python移植一份C++实现的算法发生了效果不一致的问题,经过仔细分析后发现问题竟出自For循环,由此引申此文。

详情

  首先来看看C++的For循环:

1
2
3
4
5
int i = 0;
for (i = 0; i < 5; i++) {
//do something
}

  然后再来看看根据直觉进行移植的Python代码:

1
2
3
4
i = 0
for i in range(0, 5):
# do something

  咋看之下似乎并没有问题,但若是在循环结束后输出i值,其结果竟是不一致的(C++为5,而Python为4)!在大多数情况下,C++的循环变量并不会在外部定义,所以其生存域仅在For循环之中,这种情况下并不会有什么问题。然而一旦如此,便代表i肯定要用于后续了,如此结果相差1便可让整个程序炸掉。
  仔细想来C++和Python的循环实现本就不一致,C++是使用一个逻辑值和两个表达式展开的,而Python则是一个生成器,且Python的生存域向来独树一帜,结果不一致也是理所当然的。可是在凭直觉或未了解过的情况下进行移植时便很容易中招,这便是本文的意义,以示警戒。

其他语言的For循环

  俗话说举一反三,遇到这种问题自然会想到其他编程语言关于For循环的细节,我便选择了我日常使用的Lua和C#做了尝试:

1
2
3
4
5
local n = 1
for n=1, 5 do
--do something
end
1
2
3
4
5
int i = 0;
for (i = 0; i < 5; i++) {
//do something
}

  Lua循环完毕后n的值为1,可谓相当遵守生存域了(循环是一个域,与外部变量无关)。而C#则是与C++一致,这也是理所当然的,毕竟以上代码跟C++长得完全一致嘛(估计Java也是如此)。

后记

  仔细想来编程语言之间的循环代码虽然看起来相似,但实际上他们的具体实现乃至表达式都是有所不同的,可见不可想当然,否则就容易遭遇今日这样的问题了。