Oracle PL SQL:使用标签摆脱 for 循环

Oracle PL SQL: using labels to get out of for loops

SET SERVEROUTPUT ON
BEGIN
  <<outer_loop>>
  FOR i IN 1..10 LOOP
    FOR i IN 1..3 LOOP
      EXIT outer_loop WHEN outer_loop.i = 3;
    DBMS_OUTPUT.PUT_LINE('outer i is:' || outer_loop.i || ' inner i is: ' ||i);
      GOTO goodbye;
    END LOOP;       
  END LOOP;
  <<goodbye>>
  NULL;
END;
/

我有上面的代码,它给出了下面的结果,但我的笔记说永远不要这样做。为什么会这样?毕竟它确实有效。

anonymous block completed
outer i is:1 inner i is: 1

GOTO 被认为是糟糕的编程习惯。它来自旧时代,当时旧的编程语言没有很多结构,程序员被迫使用大量的 GOTO。

GOTO 指向所谓的意大利面条代码。很难读也很难 明白了。

几乎所有语言都不鼓励使用 GOTO,主要是因为它会损害代码的可读性,是的,在您的情况下更糟 — 您正在跳过两层堆栈。

除此之外,PL/SQL 具有此功能,如果您不使用 GOTO,您会注意到这一点。它很少有用,但您的代码中的符号正是用于此目的。

比如说,你有两个这样嵌套的循环。

BEGIN
  <<outer>>
  FOR i IN 1..2 LOOP
    <<inner>>
    FOR j IN 1..2 LOOP
      dbms_output.put_line('In inner loop');
    END LOOP;

    dbms_output.put_line('In outer loop');
  END LOOP;

  dbms_output.put_line('Finished');
END;

显然,输出将是

In inner loop
In inner loop
In outer loop
In inner loop
In inner loop
In outer loop
Finished

有时您需要在循环完成之前退出循环 "normally",因此您添加 EXIT;.

BEGIN
  <<outer>>
  FOR i IN 1..2 LOOP
    <<inner>>
    FOR j IN 1..2 LOOP
      dbms_output.put_line('In inner loop');
      EXIT;
    END LOOP;

    dbms_output.put_line('In outer loop');
  END LOOP;

  dbms_output.put_line('Finished');
END;

这导致每次外循环迭代只执行一次嵌套循环。

In inner loop
In outer loop
In inner loop
In outer loop
Finished

但是您可能想要完全中止您的处理,为此您可以在嵌套循环中设置一些标志变量并在外循环中检查它的值,或者您可以指定要退出的确切循环。

BEGIN
  <<outer>>
  FOR i IN 1..2 LOOP
    <<inner>>
    FOR j IN 1..2 LOOP
      dbms_output.put_line('In inner loop');
      EXIT outer;
    END LOOP;

    dbms_output.put_line('In outer loop');
  END LOOP;

  dbms_output.put_line('Finished');
END;

这样你就退出了两个循环。

In inner loop
Finished

回到你的例子,如果你消除了 GOTO,你将在内循环的第三次迭代中退出两个循环。

我不会说这有利于提高可读性,我宁愿以某种方式通知外循环一些特殊的事情,也不愿让内循环负责从外循环退出。