修改FOR循环内的索引变量是不是很好的做法?
鉴于代码:
for (int i = 1; i <= 5; i++) { // Do work }
是否可以接受在循环中更改i
的值? 例如:
for (int i = 1; i <= 5; i++) { if( i == 2) { i = 4; } // Do work }
在我看来,这太令人困惑了。 在这种情况下更好地使用while
循环。
但是,我个人认为应该避免这种情况。 由于它创建了大多数开发人员意想不到的代码,我发现它导致了一些不太可维护的东西。
就个人而言,如果你需要这样做,我建议切换到while循环:
int i=1; while (i <= 5) { if (i == 2) i = 4; ++i; }
这至少会警告人们你使用的是非标准逻辑。
或者,如果您只是想跳过元素,请使用continue :
for (int i = 1; i <= 5; i++) { if (i == 2 || i == 3) continue; }
虽然从技术上讲,除了直接设置i
之外,还有一些操作,但对其他开发人员来说更有意义......
一个例子是删除符合某些标准的项目:
for (int i = 0; i < array.size(); /*nothing*/) { if (pred(array[i])) i++; else array.erase(array.begin() + i); }
但是更好的想法是使用迭代器:
for (auto it = array.begin(); it != array.end(); /*nothing*/) { if (pred(*it)) ++it; else it = array.erase(it); }
编辑
哦对不起,我的代码是C ++,问题是关于C#。 但不过这个想法是一样的:
for (int i = 0; i < list.Length; /*nothing*/) { if (pred(list[i])) i++; else list.RemoveAt(i); }
当然,更好的想法可能就是
list.RemoveAll(x => !pred(x));
或者稍微更现代的风格,
list = list.Where(pred);
(这里list
应该是IEnumerable<...>
)
我会说是的,但仅限于特定情况。
它可能有点令人困惑 – 如果我设置i=4
它会在下一次迭代之前递增吗?
它可能是代码味道的标志 – 也许您之前应该进行LINQ查询并且只处理相关元素?
小心使用!
是的,它可以。 由于存在极大量的可能情况,您必然会发现一个例外,它被认为是一种良好的做法。
但是,停止理论上的事情,我会说: 不 。 不要这样做。
它变得非常复杂,难以阅读和/或遵循。 我宁愿看到像continue
声明这样的东西,尽管我也不是那个人的忠实粉丝。
就个人而言,我会说,如果算法的逻辑需要一个正常线性迭代的行为,但跳过或重复某些迭代,那就去做吧。 但是,我也同意大多数人的观点,这对于循环使用来说并不正常,所以如果我在你的鞋子里,我会确保提出一两行评论,说明为什么会发生这种情况。
这种事情的完全有效的用例可能是解析罗马数字字符串。 对于字符串中的每个字符索引,请查看该字符和下一个字符。 如果下一个字符的数值大于当前字符,则从下一个字符中减去当前字符的值,将结果添加到总数中,并通过递增当前索引跳过下一个字符。 否则,只需将当前字符的值添加到运行总计中并继续。
是
您经常在解析数据的应用程序中看到它。 例如,假设我正在扫描二进制文件,而我基本上是在寻找某些数据结构。 我可能有代码执行以下操作:
int SizeOfInterestingSpot = 4; int InterestingSpotCount = 0; for (int currentSpot = 0; currentSpot < endOfFile; currentSpot++) { if (IsInterestingPart(file[currentSpot]) { InterestingSpotCount++; //I know that I have one of what I need ,and further, that this structure in the file takes 20 bytes, so... currentSpot += SizeOfInterestingSpot-1; //Skip the rest of that structure. } }
一个示例可能是for
循环,您希望在某个条件下重复当前迭代或返回上一次迭代甚至跳过一定量的迭代(而不是一个continue
)。
但这些情况很少见。 即使对于这些情况,也要考虑for
循环只是while
, do
和其他可以使用的工具中的一种方法。 所以认为这是不好的做法,并尽量避免它。 你的代码也不那么可读。
因此得出结论:它是可以实现的(不是在foreach
),而是努力避免使用while
和do
等。
引用Petar Minchev:
在我看来,这太令人困惑了。 在这种情况下更好地使用while循环。
我会说,通过这样做,你必须意识到可能发生的一些事情,例如无限循环,过早取消的循环,奇怪的变量值或基于你的索引的数学,以及主要(不排除任何其他)基于索引和故障循环修改的其他变量的执行流问题。
但如果你有这样的情况,那就去吧。