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

问题描述 投票:0回答:2
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
sql oracle-database for-loop plsql label
2个回答
7
投票

几乎在所有语言中都不鼓励使用

GOTO
,主要是因为它会损害代码的可读性,是的,在你的情况下更糟糕 - 你正在跳过两层堆栈。

除此之外,PL/SQL 还有这个简洁的 labels 功能。它很少有用,但代码中的符号正是用于此目的。

假设您有两个这样嵌套的循环。

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

有时您需要在“正常”完成之前退出循环,因此您添加

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,您将在内循环的第三次迭代中退出两个循环。

我不会说这对可读性很有好处,我宁愿以某种方式通知外循环一些特殊的东西,而不是让内循环负责从外循环退出。


3
投票

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

GOTO 会导致所谓的意大利面条代码。 读起来很难,也很难 明白了。

© www.soinside.com 2019 - 2024. All rights reserved.