突破嵌套循环


216

如果我有一个嵌套在另一个循环中的for循环,我如何以最快的方式有效地走出两个循环(内部和外部)?

我不想使用布尔值,而不必说转到另一种方法,而只是在外循环之后执行第一行代码。

有什么快速而又好的方法?

我以为异常的代价不菲,应该只在真正异常的情况下抛出异常,所以从性能的角度来看,这种解决方案不是很好。

我认为利用.NET的新功能(匿名方法)来做一些非常基础的事情是不对的。


我只是想确保:为什么要这样做?
乔恩·林贾普

3
您为什么不想使用布尔值?这样做怎么了?
安东尼

在VB.net中,您可以将try / finally语句(不捕获)包装在任意数量的循环周围,然后“退出尝试”将随时退出所有循环。
Brain2000 '18

Answers:


206

好吧,,goto但这很丑陋,并非总是可能的。您还可以将循环放入方法(或匿名方法)中,并使用return退出返回主代码。

    // goto
    for (int i = 0; i < 100; i++)
    {
        for (int j = 0; j < 100; j++)
        {
            goto Foo; // yeuck!
        }
    }
Foo:
    Console.WriteLine("Hi");

vs:

// anon-method
Action work = delegate
{
    for (int x = 0; x < 100; x++)
    {
        for (int y = 0; y < 100; y++)
        {
            return; // exits anon-method
        }
    }
};
work(); // execute anon-method
Console.WriteLine("Hi");

请注意,在C#7中,我们应该获得“本地函数”,(语法tbd等)意味着它应该类似于:

// local function (declared **inside** another method)
void Work()
{
    for (int x = 0; x < 100; x++)
    {
        for (int y = 0; y < 100; y++)
        {
            return; // exits local function
        }
    }
};
Work(); // execute local function
Console.WriteLine("Hi");

49
在这种情况下,我认为使用goto不会比break之类的常规用法更糟糕(毕竟它们都是标签的无条件分支,只是带有break的标签是隐式的)。
格雷格·比奇

37
有时goto的邪恶程度不及其他替代方法
seanb

7
@BeowulfOF-break仅会跳出内部循环,而不是内部和外部循环。
格雷格·比奇

36
Goto本身并不难看。难看的是滥用goto导致产生意大利面条式代码。完全可以使用goto打破嵌套循环。此外,请注意,从结构化编程的角度来看,所有的中断,继续和返回都比goto更好-基本上,它们是同一件事,只是包装更好。这就是纯结构语言(例如原始Pascal)缺少这三种语言的原因。
el.pescado

11
@ el.pescado是完全正确的:许多编码人员被误导认为goto本质是有害,而它只是做某些事情的正确工具,就像许多工具可能被滥用。goto坦率地说,这种宗教上的反感是愚蠢的,而且绝对是不科学的。
o0'。

96

C#中经常使用的方法的C适应-循环条件之外的外部循环变量的设置值(即,使用int变量进行循环INT_MAX -1通常是不错的选择):

for (int i = 0; i < 100; i++)
{
    for (int j = 0; j < 100; j++)
    {
        if (exit_condition)
        {
            // cause the outer loop to break:
            // use i = INT_MAX - 1; otherwise i++ == INT_MIN < 100 and loop will continue 
            i = int.MaxValue - 1;
            Console.WriteLine("Hi");
            // break the inner loop
            break;
        }
    }
    // if you have code in outer loop it will execute after break from inner loop    
}

如代码中所述,break不会神奇地跳到外循环的下一个迭代-因此,如果您的代码不在内循环中,则此方法需要进行更多检查。在这种情况下,请考虑其他解决方案。

此方法适用于forwhile循环,但不适用于foreach。如果foreach您没有对隐藏的枚举器的代码访问权限,则无法更改它(即使您IEnumerator没有某些“ MoveToEnd”方法也是如此)。

对内联评论作者的致谢: Meta的
i = INT_MAX - 1建议/ ygoe的评论。 正确的jmbpiano通过内部循环后约代码备注blizpasta
forforeach
IntMax


@DrG:在c#中不起作用,因为“ break语句终止出现在其中的最接近的封闭循环或switch语句。” (msdn)
blizpasta 2011年

1
@blizpasta那么?如果他使外循环上的条件为假(像他一样),它将同时退出。
帕特里克

51
您应该使用i = INT_MAX-1; 否则i ++在== INT_MIN <100和循环将继续

6
对foreach有任何想法吗?
ktutnik

4
@ktutnik它不适用于foreach,因为您无法访问隐藏的枚举器。IEnumerator也没有一些“ MoveToEnd”方法。
ygoe 2014年

39

此解决方案不适用于C#

对于通过其他语言找到此问题的人,Javascript,Java和D允许带标签的中断并继续

outer: while(fn1())
{
   while(fn2())
   {
     if(fn3()) continue outer;
     if(fn4()) break outer;
   }
}

40
遗憾的是,这用c#无法完成,它将在很多时候产生更清晰的代码。
里卡德2012年

17
实际上我激动了一秒钟,直到我意识到这不适合C#。:(
Arvo Bowen

1
如果有人在那里遇到问题,此概念也适用于PowerShell。(他们只是将冒号放在标签名称的前面。)现在,我知道这不是特定于PowerShell的...此语法与C#中可用的goto标签不兼容。PHP使用其他方法:打破3;将级别数放在break语句之后。
ygoe 2014年

1
这是Java而不是C#
卡·齐格勒

对于那些希望在C#中看到此功能的人,请在此处赞誉😉github.com/ dotnet
csharplang

28

在外环中使用合适的防护罩。休息之前,将防护罩设置在内环中。

bool exitedInner = false;

for (int i = 0; i < N && !exitedInner; ++i) {

    .... some outer loop stuff

    for (int j = 0; j < M; ++j) {

        if (sometest) {
            exitedInner = true;
            break;
        }
    }
    if (!exitedInner) {
       ... more outer loop stuff
    }
}

或更妙的是,将内部循环抽象为方法,并在返回false时退出外部循环。

for (int i = 0; i < N; ++i) {

    .... some outer loop stuff

    if (!doInner(i, N, M)) {
       break;
    }

    ... more outer loop stuff
}

4
除了OP所说的“我不想使用布尔值”外。
LeopardSkinPillBoxHat

非常帕斯卡式的...我可能宁愿使用goto,尽管我通常像瘟疫一样避开它们。
乔纳森·莱夫勒

21

不要在此引用我,但是您可以按照MSDN中的建议使用goto。还有其他解决方案,包括在两个循环的每次迭代中都检查一个标志。最后,您可以将异常用作解决您问题的重量级解决方案。

去:

for ( int i = 0; i < 10; ++i ) {
   for ( int j = 0; j < 10; ++j ) {
      // code
      if ( break_condition ) goto End;
      // more code
   }
}
End: ;

健康)状况:

bool exit = false;
for ( int i = 0; i < 10 && !exit; ++i ) {
   for ( int j = 0; j < 10 && !exit; ++j ) {
      // code
      if ( break_condition ) {
         exit = true;
         break; // or continue
      }
      // more code
   }
}

例外:

try {
    for ( int i = 0; i < 10 && !exit; ++i ) {
       for ( int j = 0; j < 10 && !exit; ++j ) {
          // code
          if ( break_condition ) {
             throw new Exception()
          }
          // more code
       }
    }
catch ( Exception e ) {}

2
这些都是骇人的解决方法,将其分解为一种方法并使用早期回报将非常干净
Dustin Getz

3
:)正确的,这是一个简单的解决方案,但你必须对所有所需的本地数据传递到方法的参数......这是少数地方转到可能是合适的解决方案之一
大卫·罗德里格斯- dribeas

Condition方法甚至不起作用,因为“更多代码”将在退出内部循环之后,退出外部循环之前执行一次。GOTO方法有效,但确实执行了张贴者所说的不想执行的操作。Exception方法有效,但比GOTO丑陋且慢。
Windows程序员

我会在标签后突出显示该分号。这样,标签甚至可以位于块的末尾。+1
Tamas Hegedus

@Windowsprogrammer OP询问:“快速而又不错的方法是什么?” Goto是首选的解决方案:简洁简洁,无需使用其他方法。
Suncat2000

16

是否可以将嵌套的for循环重构为私有方法?这样,您可以简单地“返回”该方法以退出循环。


具有使您的原始方法更短的附带好处:-)
Martin Capodici 2012年

C ++ 11 lambdas在某些情况下使此操作变得容易:[&] { ... return; ... }();
BCS

14

在我看来,人们似乎非常不喜欢这种goto说法,所以我觉得有必要理清这一点。

我相信人们的“情感” goto最终归结为对代码的理解以及对可能的性能影响的(误解)。因此,在回答问题之前,我将首先介绍有关如何编译的一些细节。

众所周知,C#被编译为IL,然后使用SSA编译器将其编译为汇编器。我将对所有这些工作原理有一些见解,然后尝试回答问题本身。

从C#到IL

首先,我们需要一段C#代码。让我们开始简单:

foreach (var item in array)
{
    // ... 
    break;
    // ...
}

我将逐步进行此操作,以使您对幕后发生的事情有个很好的了解。

第一个翻译:从foreach到等效for循环(注意:我在这里使用数组,因为我不想深入了解IDisposable的详细信息-在这种情况下,我还必须使用IEnumerable):

for (int i=0; i<array.Length; ++i)
{
    var item = array[i];
    // ...
    break;
    // ...
}

第二种翻译:forbreak被翻译成更容易的等价形式:

int i=0;
while (i < array.Length)
{
    var item = array[i];
    // ...
    break;
    // ...
    ++i;
}

和第三翻译(这是等效的IL代码):我们改变breakwhile进入了一个分支:

    int i=0; // for initialization

startLoop:
    if (i >= array.Length) // for condition
    {
        goto exitLoop;
    }
    var item = array[i];
    // ...
    goto exitLoop; // break
    // ...
    ++i;           // for post-expression
    goto startLoop; 

尽管编译器只需一步即可完成这些操作,但它可以让您深入了解该过程。从C#程序演变而来的IL代码是最后C#代码的字面翻译。您可以在这里自己看到:https : //dotnetfiddle.net/QaiLRz(单击“查看IL”)

现在,您在这里观察到的一件事是,在此过程中,代码变得更加复杂。观察这一点的最简单方法是,我们需要越来越多的代码来说明同一件事。您可能还认为foreachforwhilebreak实际上短期手中goto,这部分是真实的。

从IL到汇编器

.NET JIT编译器是SSA编译器。我不会在这里讨论SSA表单的所有详细信息以及如何创建优化的编译器,这虽然太多了,但可以对将会发生的事情提供基本的了解。为了获得更深入的了解,最好开始阅读优化编译器(我确实喜欢这本书作为简短介绍:http : //ssabook.gforge.inria.fr/latest/book.pdf //ssabook.gforge.inria.fr/latest/book.pdf)和LLVM(llvm.org) 。

每个优化的编译器都依赖于这样的事实,即代码很容易并且遵循可预测的模式。对于FOR循环,我们使用图论来分析分支,然后在分支中优化诸如Cycli之类的东西(例如,向后分支)。

但是,我们现在有了前向分支来实现我们的循环。您可能已经猜到了,这实际上是JIT要修复的第一步,如下所示:

    int i=0; // for initialization

    if (i >= array.Length) // for condition
    {
        goto endOfLoop;
    }

startLoop:
    var item = array[i];
    // ...
    goto endOfLoop; // break
    // ...
    ++i;           // for post-expression

    if (i >= array.Length) // for condition
    {
        goto startLoop;
    }

endOfLoop:
    // ...

如您所见,我们现在有一个向后分支,这是我们的小循环。这里唯一仍然令人讨厌的是由于我们的break声明而最终导致的分支。在某些情况下,我们可以以相同的方式移动它,但在其他情况下,它仍然存在。

那么,为什么编译器会这样做呢?好吧,如果我们可以展开循环,则可以对它进行矢量化处理。我们甚至可以证明只添加了常量,这意味着我们的整个循环可能消失了。总结:通过使模式可预测(使分支可预测),我们可以证明某些条件存在于我们的循环中,这意味着我们可以在JIT优化过程中做魔术。

但是,分支趋向于破坏那些很好的可预测模式,这是优化程序所不喜欢的。打破,继续,前进-他们都打算打破这些可预测的模式-因此并不是真正的“好”。

在这一点上,您还应该认识到,比起遍布各处foreach的一堆goto语句,更容易预测。从(1)可读性和(2)从优化器的角度来看,这都是更好的解决方案。

值得一提的另一件事是,优化编译器将寄存器分配给变量(称为寄存器分配的过程)非常重要。您可能知道,CPU中只有有限数量的寄存器,它们是迄今为止硬件中最快的内存。最内层循环中的代码中使用的变量更有可能分配一个寄存器,而循环外的变量则不太重要(因为此代码的命中率可能会降低)。

帮助,太复杂了...我该怎么办?

最重要的是,您应该始终使用您可以使用的语言构造,这通常(隐式)将为编译器构建可预测的模式。尽量避免陌生的分支(如果可能具体是:breakcontinuegotoreturn在没有任何中间)。

好消息是这些可预测的模式既易于阅读(对于人类)又易于发现(对于编译器)。

这些模式之一称为SESE,它表示单入口单出口。

现在我们解决了真正的问题。

假设您有这样的事情:

// a is a variable.

for (int i=0; i<100; ++i) 
{
  for (int j=0; j<100; ++j)
  {
     // ...

     if (i*j > a) 
     {
        // break everything
     }
  }
}

使这种模式可预测的最简单方法是完全消除以下内容if

int i, j;
for (i=0; i<100 && i*j <= a; ++i) 
{
  for (j=0; j<100 && i*j <= a; ++j)
  {
     // ...
  }
}

在其他情况下,您也可以将方法分为2种方法:

// Outer loop in method 1:

for (i=0; i<100 && processInner(i); ++i) 
{
}

private bool processInner(int i)
{
  int j;
  for (j=0; j<100 && i*j <= a; ++j)
  {
     // ...
  }
  return i*j<=a;
}

临时变量?好不好还是丑陋?

您甚至可能决定从循环内返回一个布尔值(但我个人更喜欢SESE形式,因为这是编译器将其看到的方式,并且我认为它更易于阅读)。

有人认为使用临时变量比较干净,并提出如下解决方案:

bool more = true;
for (int i=0; i<100; ++i) 
{
  for (int j=0; j<100; ++j) 
  {
     // ...
     if (i*j > a) { more = false; break; } // yuck.
     // ...
  }
  if (!more) { break; } // yuck.
  // ...
}
// ...

我个人反对这种方法。再看一下代码是如何编译的。现在考虑一下如何使用这些好的可预测模式。拿图片吗

是的,让我说清楚。将会发生的是:

  • 编译器会将所有内容写为分支。
  • 作为优化步骤,编译器将进行数据流分析,以尝试删除more仅在控制流中使用的奇怪变量。
  • 如果成功,该变量more将从程序中删除,仅保留分支。这些分支将得到优化,因此您只能从内部循环中获得一个分支。
  • 如果不成功,则该变量more肯定会在最内层循环中使用,因此,如果编译器无法对其进行优化,则很有可能将其分配给寄存器(这会耗尽宝贵的寄存器内存)。

因此,总而言之:编译器中的优化器将陷入困境,以至于找出more仅用于控制流的情况,并且在最佳情况下,会将其转换为外部的单个分支,以便循环。

换句话说,最好的情况是最终将达到以下效果:

for (int i=0; i<100; ++i) 
{
  for (int j=0; j<100; ++j)
  {
     // ...
     if (i*j > a) { goto exitLoop; } // perhaps add a comment
     // ...
  }
  // ...
}
exitLoop:

// ...

我对此的个人意见很简单:如果这一直是我们一直想要的目标,那么让我们简化编译器和可读性的工作,并立即编写它。

tl; dr:

底线:

  • 如果可能,在for循环中使用简单的条件。尽可能使用您可以使用的高级语言构造。
  • 如果一切都失败了,或者您选择了gotobool more,则最好选择前者。

OTOH:我很少有打破外部循环的愿望,或者渴望goto-equiv的愿望(而且很多确实可以更清晰地编写代码),尽管在其他领域这种情况可能更常见。.今天是这种情况,但这主要是由于yield return。也就是说,虽然很容易显示出一些有用的情况,但是对于大多数“应用程序级”代码,C#挫败感发生的可能性很小,除了那些“仅来自” C / C ++之外;-)我偶尔也会错过Ruby的“抛出”(非异常展开)有时也适用于此领域。
user2864740 '17

1
@ Suncat2000只是引入更多代码,例如变量和条件分支,以避免使用goto,不会使您的代码更具可读性-我认为发生的事情是完全相反的:实际上,您的控制流将包含更多节点-这几乎是复杂性的定义。只是避免使用它来帮助自律听起来在可读性方面适得其反。
至少在

@atlaste:对不起,让我更清楚地陈述我的评论。我应该说的是:很好的解释。但是,人们避免使用goto与性能无关;这是关于避免导致缺乏可读性的滥用。我们可以假设那些避免的人goto就是没有纪律不滥用它。
Suncat2000

@atlaste,“ ackpmplish”是什么语言?
Pacerier

11

将其分解为函数/方法并使用及早返回,或将循环重新安排为有条件的子句。goto / exceptions /无论什么都不适合这里。

def do_until_equal():
  foreach a:
    foreach b:
      if a==b: return

10

您要求快速,不错,不使用布尔值,不使用goto和C#的组合。您已经排除了所有可能的方式来做自己想要的事情。

最快捷最丑陋的方法是使用goto。


完全同意。仅仅为了摆脱单个goto引入一种新方法是很愚蠢的。如果编译器由于某种原因无法内联该方法调用,则最终将导致完全不必要的额外方法调用开销。仅仅为了打破循环而抛出和捕获异常既冗长又荒谬,代价更高。
Zar Shardan

@ Windowsprogramm:OP没有要求“不使用goto”。他不想“去另一种方法”。问题远没有排除所有可能的方法,但是您正确地暗示goto在这里是最好的。
Suncat2000

5

有时将代码抽象到自己的函数中比使用早期返回更好-尽管早期返回很邪恶:)

public void GetIndexOf(Transform transform, out int outX, out int outY)
{
    outX = -1;
    outY = -1;

    for (int x = 0; x < Columns.Length; x++)
    {
        var column = Columns[x];

        for (int y = 0; y < column.Transforms.Length; y++)
        {
            if(column.Transforms[y] == transform)
            {
                outX = x;
                outY = y;

                return;
            }
        }
    }
}

1
但是,这允许使用OP提出的传统解决方案
Surya Pratap 2014年

2

我看过很多使用“ break”的示例,但是没有使用“ continue”的示例。

在内部循环中仍然需要某种标志:

while( some_condition )
{
    // outer loop stuff
    ...

    bool get_out = false;
    for(...)
    {
        // inner loop stuff
        ...

        get_out = true;
        break;
    }

    if( get_out )
    {
        some_condition=false;
        continue;
    }

    // more out loop stuff
    ...

}

1

自从我break几十年前第一次在C语言中看到以来,这个问题困扰着我。我希望某些语言增强功能可以打破常规,从而可以解决问题:

break; // our trusty friend, breaks out of current looping construct.
break 2; // breaks out of the current and it's parent looping construct.
break 3; // breaks out of 3 looping constructs.
break all; // totally decimates any looping constructs in force.

3
然后,维护程序员将插入另一级嵌套,将修复一些break语句,并破坏其他一些break语句。解决方法是改为打断标签。确实有人提出过这个建议,但实用主义者改用goto标签。
Windows程序员

等一下,谁再进行维护编程?:)
Jesse C. Slicer

2
JavaScript甚至具有标记的block / break语句。devguru.com/Technologies/ecmascript/quickref/break.html
David Grant

@克里斯·巴托:太酷了!做了我的圣诞节:) @David Grant:看来JS break == C的goto了吗?
Jesse C. Slicer,

d已标记突破/继续
BCS

0

我记得从我的学生时代起,就曾有人说过,在数学上可以证明无需goto即可在代码中执行任何操作(即,在任何情况下goto都是唯一的答案)。因此,我从不使用goto的功能(只是我的个人喜好,并不表示我是对还是错)

无论如何,为了摆脱嵌套循环,我可以执行以下操作:

var isDone = false;
for (var x in collectionX) {
    for (var y in collectionY) {
        for (var z in collectionZ) {
            if (conditionMet) {
                // some code
                isDone = true;
            }
            if (isDone)
                break;
        }
        if (isDone) 
            break;
    }
    if (isDone)
        break;
}

...我希望对像我这样的人有帮助,反对反“粉丝” :)


不好意思告诉您,但您的讲师是您状况的原因。如果他不愿意强迫您学习汇编语言,那么您会知道“ goto”只是一个跳跃(当然,我忽略了这是ac#问题的事实)。
cmroanirgo

0

那就是我做到的。仍然是一种解决方法。

foreach (var substring in substrings) {
  //To be used to break from 1st loop.
  int breaker=1;
  foreach (char c in substring) {
    if (char.IsLetter(c)) {
      Console.WriteLine(line.IndexOf(c));
      \\setting condition to break from 1st loop.
      breaker=9;
      break;
    }
  }
  if (breaker==9) {
    break;
  }
}


0

结束双循环的最简单方法是直接结束第一个循环

string TestStr = "The frog jumped over the hill";
char[] KillChar = {'w', 'l'};

for(int i = 0; i < TestStr.Length; i++)
{
    for(int E = 0; E < KillChar.Length; E++)
    {
        if(KillChar[E] == TestStr[i])
        {
            i = TestStr.Length; //Ends First Loop
            break; //Ends Second Loop
        }
    }
}

这不起作用,因为使用break会结束内部循环。外循环将继续迭代。
Alex Leo

0

可以使用循环中的自定义条件来破坏循环,从而获得清晰的代码。

    static void Main(string[] args)
    {
        bool isBreak = false;
        for (int i = 0; ConditionLoop(isBreak, i, 500); i++)
        {
            Console.WriteLine($"External loop iteration {i}");
            for (int j = 0; ConditionLoop(isBreak, j, 500); j++)
            {
                Console.WriteLine($"Inner loop iteration {j}");

                // This code is only to produce the break.
                if (j > 3)
                {
                    isBreak = true;
                }                  
            }

            Console.WriteLine("The code after the inner loop will be executed when breaks");
        }

        Console.ReadKey();
    }

    private static bool ConditionLoop(bool isBreak, int i, int maxIterations) => i < maxIterations && !isBreak;   

使用此代码,我们获得以下输出:

  • 外部循环迭代0
  • 内循环迭代0
  • 内循环迭代1
  • 内循环迭代2
  • 内循环迭代3
  • 内循环迭代4
  • 内部循环后的代码将在中断时执行

0

另一种选择是自调用匿名函数。与顶部的匿名方法示例相比,没有goto,没有标签,没有新变量,没有使用任何新函数名,而且仅短了一行。

// self-invoked-anonymous-function
new Action(() =>
{
    for (int x = 0; x < 100; x++)
    {
        for (int y = 0; y < 100; y++)
        {
            return; // exits self invoked lambda expression
        }
    }
})();
Console.WriteLine("Hi");

-3

抛出一个自定义异常,该异常会向外循环。

它适用于forforeachwhile任何种类的循环和使用try catch exceptionblock的任何语言

try 
{
   foreach (object o in list)
   {
      foreach (object another in otherList)
      {
         // ... some stuff here
         if (condition)
         {
            throw new CustomExcpetion();
         }
      }
   }
}
catch (CustomException)
{
   // log 
}

-4
         bool breakInnerLoop=false
        for(int i=0;i<=10;i++)
        {
          for(int J=0;i<=10;i++)
          {
              if(i<=j)
                {
                    breakInnerLoop=true;
                    break;
                }
          }
            if(breakInnerLoop)
            {
            continue
            }
        }

dviljoen的答案有什么本质区别?
Gert Arnold

那是行不通的,因为您没有在外部for循环中检查“ breakInnerLoop”条件,所以您仅迭代到下一个循环,还编写了j和J,并错过了分号,该分号将无法编译。
塞巴斯蒂安

-4

正如我所见,您接受了一个人引用您的goto语句的答案,在现代编程和专家看来,goto是一个杀手,我们称它为编程中的杀手,由于某些原因,在此不再赘述。在这一点上,但是您问题的解决方案非常简单,您可以在这种情况下使用布尔标志,就像我将在示例中演示的那样:

            for (; j < 10; j++)
            {
                //solution
                bool breakme = false;
                for (int k = 1; k < 10; k++)
                {
                   //place the condition where you want to stop it
                    if ()
                    {
                        breakme = true;
                        break;
                    }
                }

                if(breakme)
                    break;
               }

简单明了。:)


在建议休息之前先阅读问题。因此,反对票。
cmroanirgo

1
立即阅读,但是当我发布此答案时,未添加不使用boolean的编辑版本,这就是为什么我发布此答案的原因..但是感谢downvote!
史蒂夫(Steve)

1
这不是个人的事。不幸的是,现在投票已锁定;)这是SO获得高层最佳答案的必要部分(并非总是如此)
cmroanirgo

-6

你甚至看过 break关键字吗?o

这只是伪代码,但是您应该能够理解我的意思:

<?php
for(...) {
    while(...) {
        foreach(...) {
            break 3;
        }
    }
}

如果你想break成为一个像break(),那么它的参数就是要中断的循环数。由于我们处于此处代码的第三个循环中,因此我们可以突破所有这三个条件。

手册:http : //php.net/break


13
不是PHP的问题。
Zerga 2014年

-10

我认为除非您要执行“布尔值”操作,否则唯一的解决方案实际上是抛出。您显然不应该这样做..!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.