Delphi 德尔菲:在这种情况下,Goto不被认为是有害的吗?

Delphi 德尔菲:在这种情况下,Goto不被认为是有害的吗?,delphi,goto,Delphi,Goto,好的,现在有一个TObjectList实例。您希望循环浏览其中的项目,并从列表中删除一些对象。你不能这样做: for I := 0 to ObjectList.Count - 1 do if TMyClass(ObjectList[I]).ShouldRemove then ObjectList.Delete(I); …因为一旦删除第一个对象,索引计数器I将全部出错,循环将不再工作 因此,我的解决方案如下: Again: for I := 0 to ObjectList.Cou

好的,现在有一个TObjectList实例。您希望循环浏览其中的项目,并从列表中删除一些对象。你不能这样做:

for I := 0 to ObjectList.Count - 1 do
  if TMyClass(ObjectList[I]).ShouldRemove then
    ObjectList.Delete(I);
…因为一旦删除第一个对象,索引计数器I将全部出错,循环将不再工作

因此,我的解决方案如下:

Again:
  for I := 0 to ObjectList.Count - 1 do
    if TMyClass(ObjectList[I]).ShouldRemove then
    begin
      ObjectList.Delete(I);
      goto Again;
    end;
这是迄今为止我找到的最好的解决方案。如果有人有更整洁的解决方案,我很想看看。

试试这个:

 for I := ObjectList.Count - 1 downto 0 do
   if TMyClass(ObjectList[I]).ShouldRemove then
     ObjectList.Delete(I);
这看起来是goto的一个特别糟糕的用法,像那样跳出for循环。我认为它是有效的(因为您正在使用它),但它会让我感到不安。

我见过的Goto的唯一有效用法是Delphi的帮助中提供的用法

for I := 0 to something do
begin
  for J := 0 to something do
  begin
    For K := 0 to something do
    begin
      if SomeCondition then
        Goto NestedBreak
    end;
  end;
end;
NestedBreak:
尽管在该示例中,可以通过在本地函数中移动循环并使用EXIT来避免Goto,例如。如果子功能不可接受,您仍然可以执行以下操作:

for I := 0 to something do
begin
  for J := 0 to something do
  begin
    For K := 0 to something do
    begin
      if SomeCondition then
      begin
        GottaBreak := True
        Break;
      end; 
    end;
    if GottaBreak then Break;
  end;
  if GottaBreak then Break;
end;
这只是稍微不太理想

我还没有看到任何其他情况下,Goto将是最好的解决方案(或任何好的)

后藤本身并不坏。这是一个流控制命令,就像退出、中断或继续一样。除此之外,其他限制在特定情况下,并由编译器正确管理。(也就是说,我所说的一些程序员认为那些和Goto一样有害,一个我不认同的观点)是不受限制的,你能用它做的事情会产生非常负面的影响。无论如何,我想我已经超出了问题的范围了^_^

您也可以使用

  I := 0;
  while I < ObjectList.Count do begin
    if TMyClass(ObjectList[I]).ShouldRemove then ObjectList.Delete(I)
    else Inc(I);
  end;
I:=0;
当我
等等。。。这是否意味着在Delphi中,
ObjectList[k]
具有复杂性O(k)(当
ObjectList
是一个列表时)?在这种情况下,您的算法具有错误的复杂性。如果您正在处理列表,您应该对列表进行正确的操作,并且不要为循环编写
,这样您就不会对
转到(尽管您可能会对异常感到疑惑)。我之所以循环,是因为我想从列表中删除几个项目。否则我只使用ObjectList.Remove(ObjectToRemove)@David我了解那么多,也许我不应该对我不太熟悉的语言发问,但是如果
ObjectList[k]
的复杂性为O(k)(我怀疑是的),那么您的实现语言会迫使您编写复杂度错误的算法。是时候转换了。。。有一些语言可以从O(长度)的列表中删除您应该删除的元素。ObjectList[k]直接访问对象。它不需要通过0..k循环找到正确的对象。@david Fair,我在这里的深度不够(尽管我希望看到该数据结构的实现,该数据结构允许您删除某些元素,但对第n个元素有O(1)个访问时间)。哇。这是可行的,我不是100%确定为什么,但我只是测试了它,它做到了。很好。好吧,我明白为什么它现在起作用了。因为你在倒计时,所以列表缩小并不重要。随后的索引都将是有效的。我现在要去更改我的愚蠢代码。请记住,Larry的解决方案是这个特定问题(基于索引的删除)的一个众所周知的标准解决方案,适用于比“Delphi”和/或“TObjectList”更多的情况。这是一个重要的工具,可以放在你的腰带上。基本上,它表明,对于这个问题,仍然不需要使用Goto在我20年的PASCAL编程经验中,我知道如果你考虑使用Goto,那么你将错过一个更好的解决方案。我从来都不需要使用这个愚蠢的命令。肯,你可以尝试一下……除了循环和使用Abort;而不是goto。我想我更喜欢。例外情况有很多。。。比“if GottaBreak then”解决方案对性能的影响要大得多。尝试…除了对性能不好。它不应该用于“正常”流。今天的处理器速度足够快,您不必担心引发单个异常以从循环中逃脱对性能的影响。今天的处理器有这么多性能,让我们浪费一些吧!说真的,这里有一些读物给你@肯,谢谢,那是一本很有趣的书。我没有意识到异常会对性能造成如此大的影响。从现在起,我将避免在正常的程序流中使用它们。这也是一个很好的解决方案!谢谢,是的!好的。但是做一个反向循环怎么样<如果TMyClass(ObjectList[I])应该删除,那么ObjectList.Delete(I)?已经建议过了。:-)