我刚刚发现...再次 ...实时浪费错误如下

for (int i = 0; i < length; i++)
{ //...Lots of code 
    for (int j = 0; i < length; j++)
    {
        //...Lots of code 
    }
}

您是否注意到前面的内部 i 应该是 j ?我也不。所以从现在开始我将使用:

for (int i = 0; i < length; i++)
{
    for (int i1 = 0; i1 < length; i1++)
    {
    }
}

对于内部和外部 while 和 for 循环有哪些技巧?

编辑:感谢您的宝贵回复。以下是建议提示的简短摘要:

  • 对索引变量使用有意义的变量名称(而不是我使用 SomeObjCollectionLength )
  • 将内部循环的内容放入单独的方法中,并从外部循环调用该方法
  • 外循环和内循环之间的代码行数量无法管理,这是代码异味的强烈信号
  • 避免复制粘贴和匆忙,小心编写索引变量

您可能想通过以下方式检查摘要 布什金 为了 下列的

  • 尽可能使用 foreach 和迭代器
  • 在进入循环之前初始化变量
  • 使每个循环只执行一项功能。避免在单个循环中混合职责
  • 如果可能的话,让循环足够短,以便一次查看所有内容
有帮助吗?

解决方案

不要使用 i 和 j(或任何其他单字母变量)作为索引名称。使用正确的名称,您就不会遇到此类问题。

其他提示

最简单、最干净的解决方案之一是将内部循环的内容放入方法中,使其变为:

for (int i = 0; i < length; i++)
{
    DoSomething();
}

private void DoSomething(int outerValue)
{
    for (int i = 0; i < length; i++)
    {
        // Do something else
    }

}

对我来说,这里的“代码味道”是“大量代码”。

如果循环中的代码量特别大,则内循环和外循环之间的距离意味着不太可能相互比较它们的正确性。

诚然,单独查看内部循环的开始应该会让您注意到这个问题,但是将主要结构放在尽可能小的代码段中会让您的大脑更少消化。

可以将“大量代码”部分提取到单独的函数/方法中,以减少主结构的大小 - 但这可能并不总是可行的。

另外,我想说“i1”并不是一个特别好的变量名称选择,因为这往往会鼓励“i2”、“i3”等,而这并不能真正产生可理解的代码。也许用更有意义的东西替换所有循环变量将有助于代码的清晰度,并减少原始错误的可能性。

我对编写更好的循环代码的首要建议(排名不分先后)(其中大部分来自优秀的书 代码完成):

  1. 避免循环有多个退出点。
  2. 谨慎使用继续/中断。
  3. 如果可能,将嵌套循环重构为单独的例程。
  4. 使用有意义的变量名称使嵌套循环可读。
  5. 尽可能使用 foreach() 循环,而不是 for(i=...) 循环。
  6. 仅从一个位置进入循环。不要用 goto 跳入循环。曾经。
  7. 将初始化代码放在循环之前。
  8. 将循环初始化语句与它们相关的循环保留在一起。
  9. 避免在非嵌套循环之间重用变量。10.将循环索引变量的范围限制为循环本身。
  10. 使用 while(true) 进行无限循环,而不是 for(;;)
  11. 在提供块结构的语言中(例如'{' 和 '}') 使用它们而不是缩进来包围循环语句。是的,即使对于单线循环也是如此。
  12. 避免空循环。
  13. 避免将家务杂务放在循环的中间,而是将它们放在开头和/或结尾。
  14. 使每个循环只执行一项功能。避免在单个循环中混合职责。
  15. 使循环终止条件明显。
  16. 不要胡闹 for() 循环的循环索引变量以使其终止。
  17. 避免依赖循环索引器最终值的代码。
  18. 考虑在复杂循环中使用安全计数器 - 可以检查它们以确保循环不会执行太多或太少。
  19. 如果可能的话,使用break语句来终止while循环。
  20. 如果可能,请使循环足够短,以便一次查看所有内容。

这是复制粘贴错误,避免复制粘贴。

至于你的解决方案,它并没有好多少。错误仍然可能在大量代码之间溜走。即使对于循环临时变量,我也倾向于使用有意义的名称。

利用你的IDE,在VS上,尝试使用这个: http://msdn.microsoft.com/en-us/library/z4c5cc9b(VS.80).aspx

样本:类型 为了, ,然后按 选项卡 选项卡 依次

我来这里是为了聪明地说“我第一次就写对了”。但后来我看到了你的例子,嗯,我自己也这样做过太多次了。

当你需要这样的嵌套循环时,我唯一的解决方案就是在编写代码时保持警惕和思考。

在可能的情况下,使用迭代器和 foreach 循环是很好的选择。

另外,我看不出您建议的解决方案会更好。而且看起来也不那么好看。

首先,减小循环体的大小,即将东西移动到单独的功能中。通常,函数的长度超过屏幕所能容纳的长度是一个坏主意,因此循环应该更小。

其次,在这种情况下使用有意义的变量名称。我只会在简单的循环中使用 i 和 j 并使用几行代码。例如,如果您正在处理二维数组,“col”和“row”会更有意义,使代码更易于阅读(“哪个是哪个?”)并且更容易发现此类错误。

你只需要额外注意这些问题,没有什么灵丹妙药可以解决这个问题。即使有“更好的命名”,您建议您偶尔也会忘记这是第 N 级还是第 (N+M) 级嵌套循环并犯错误。

如果需要嵌套循环,请仔细书写。如果可以通过将外循环体提取到函数中来避免这种情况,那么可以很好地防止索引滥用。

如果我确实需要它们,我会使用“ii”和“jj”作为瞬态循环计数器 - 它们比“i”和“j”更容易搜索,并且在上面的示例中也更容易发现。为了更好,您实际上可以使用真实的变量名称。如果你要循环一个字符串,那么你可以将其称为“characterIndex”或其他名称。它需要更多的打字,但它可以自我记录并节省以后调试模糊问题的时间。

更好的是避免使用数字计数器并在集合上使用命名迭代器。在我看来,它们使意图更加清晰。

最后,如果可能的话,最好完全取消循环: 提升::Foreach 是在 C++ 中执行此操作的一种方法,尽管我通常更喜欢使用 Python 等语言,这些语言本身允许直接迭代容器的内容,而不需要增加索引值或迭代器。

尝试使用更具声明性的循环结构。例如,如果您真的不需要索引(那些 ijs) 并且您的编程环境允许,您可以使用 foreach 构造迭代集合。

正如在这方面和许多事情一样,史蒂夫·麦康奈尔(Steve McConnell)的书中有一些极好的建议 代码完成. 。非常值得您花时间阅读他关于构建良好循环代码的内容。我手边没有这本书的副本,但整本书值得您花时间。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top