在delphi中使用'GoTo'命令?

时间:2014-02-13 11:10:05

标签: delphi

我读到使用Goto命令是非常糟糕的,可能会弄乱你的代码。我还读到有一项民意调查显示,如果他们看到goto命令和delphi在一起,而另外40%的人甚至不知道goto命令,那么40%的Delphi开发人员会非常交叉那是为什么?

但无论如何,我正在制作一个程序,通过获得两个分数并获得这两个分数的平均值来检查你是否有资格获得助学金。为了获得助学金,您需要达到90%或更高的平均值,它将在标签中显示您的平均值,如果您符合其他标签的资格。我最近也了解了If命令,现在我正忙着玩它。

这是我的代码:

procedure TForm1.btnCalcClick(Sender: TObject);
var
  iMaths, iScience, iAvarage   :   integer;

begin
  iScience := sedScience.value;
  iMaths   := sedMath.value;
  iAvarage := round((iMaths+iScience)/2);

  if iMaths = 0
    then
      begin
      showmessage ('Sorry, please put a propper value in the Maths and Science box!');
    end;

    if iAvarage >= 90
     then
        begin
          lblAvarage.caption := 'Your avarage is: ' + IntToStr (iAvarage);
          lblOutput.caption := 'You qualify for an Einstein Bursary!';
        end
    else
        begin
          lblAvarage.Caption := 'Your avarage is ' + IntToStr (iAvarage);
          lblOutput.caption := 'Sorry, you do not qualify for an Einstein bursary.';
        end;
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
  begin
    sedMath.value := 0;
    sedScience.value := 0;
    lblAvarage.caption := ' ';
    lblOutput.caption := ' ';
    sedMath.setfocus
  end;

end. 

我说if iMaths = 0只是确保SpinEdit中有一个值,如果没有,它必须在ButtonClick处理程序中重新启动,并显示一条消息Please insert a proper value。一切正常,但它仍然显示标签中的平均值(lblOutput和lblAvarage),我不希望它这样做!

如果我使用goto命令,我认为它应该是这样的:

procedure TForm1.btnCalcClick(Sender: TObject);
var
  iMaths, iScience, iAvarage   :   integer;
label
  lRestart;
begin
  lRestart;
  iScience := sedScience.value;
  iMaths   := sedMath.value;
  iAvarage := round((iMaths+iScience)/2);

  if iMaths and iScience = 0
    then
      begin
      showmessage ('Sorry, please put a propper value in the Maths and Science box!');
      goto lRestart;
    end;

(顺便说一句,我知道上面的代码错了,我试过了!)

我用Google搜索goto,但我找到的东西与我需要的东西不同。

非常感谢有关如何使用goto命令的任何帮助或建议!

2 个答案:

答案 0 :(得分:6)

goto的语法不正确。它应该是:

procedure TForm1.btnCalcClick(Sender: TObject);
....
label
  lRestart;
begin
lRestart:
  ....
  goto lRestart;
  ....
end;

但是如果你想做这样的事情,你肯定会通过这样写出来避免goto

repeat
  // do something
until OkToContinue;

那就是说,你的代码应该是:

procedure TForm1.btnCalcClick(Sender: TObject);
var
  iMaths, iScience, iAverage: integer;
begin
  iScience := sedScience.value;
  iMaths   := sedMath.value;
  iAverage := round((iMaths+iScience)/2);

  if (iMaths=0) or (iScience=0) then
  begin
    ShowMessage('Sorry, please put a propper value in the Maths and Science box!');
    exit;
  end;

  // do the calculation
end;

您的事件处理程序中不需要循环或goto。您必须在发现错误时退出,并让用户有机会修复错误并再次单击该按钮。因此,您只需要完全错误地认为您需要goto

我猜你还没有完全掌握事件驱动编程的概念。如果你回到开头而不是退出程序,用户就没有机会修改旋转编辑控件的值,你会一次又一次地显示消息。试一试,看看我的意思。

另请注意,我在您的代码中修复了许多其他错误。


至于goto,我相信你永远不会需要它。我只发现goto在不支持结构化异常的语言中有用。德尔福不属于那个阵营。

答案 1 :(得分:2)

您不需要在程序中使用goto

不使用它的一些原因,因为在大多数情况下:

  • 这会降低您的代码的可读性;
  • 可以很容易地将其转换为嵌套的repeat .. untilwhile ..结构,这些结构通常具有相同的精确时序(将编译为汇编程序jmp ..操作码。

有时,将repeat .. untilwhile ..结构条件表达式放在循环中可能会稍快一些,并使用{ {1}}和break以及continuerepeat .. until false

while true do ..

将使用非常优化的汇编程序编译:

function GotoEndOfJSONString(P: PUTF8Char): PUTF8Char;
begin // P^='"' at function call
  inc(P);
  repeat
    if P^=#0 then
      break else
    if P^<>'\' then
      if P^<>'"' then
        inc(P) else
        break else
      inc(P,2);
  until false;
  result := P;
end; // P^='"' at function return

但这对于非常低级别的代码来说可能是值得的,并且会降低其可读性。编写这样的代码非常接近直接编写汇编程序代码:您知道 inc eax @s: mov dl,[eax] test dl,dl jz @e cmp dl,$5c je @2 cmp dl,$22 je @e inc eax jmp @s @2: add eax,2 jmp @s @e: ret break将转换为直接continue汇编程序操作码。

我使用jmp ..的唯一情况是在一些明确定义的条件下:

  • 确定低级数据处理(例如文本处理);
  • 仅出于表现原因;
  • 通过适当的单元测试(因为代码不太可读);
  • goto内部块之间或从一个循环到另一个循环之间需要分支时;
  • 当我想避免在旧版本的Delphi(例如Delphi 7)中调用子过程时 - 但在现代Delphi中,case .. of可以用goto本地过程替换。

一些例子:

inline

作为结论,在纯粹的pascal或某些低级代码的 FastCode质询之外,您不应再看到任何procedure TTextWriter.AddJSONEscape(P: Pointer; Len: PtrInt); var c: PtrUInt; label Esc, nxt; begin if P=nil then exit; if Len=0 then Len := MaxInt; if B>=BEnd then Flush; repeat inc(B); // escape chars, according to http://www.ietf.org/rfc/rfc4627.txt c := PByte(P)^; if c>=32 then begin if c in [ord('\'),{ord('/'),}ord('"')] then goto Esc; B^ := AnsiChar(c); nxt: if Len=1 then break; dec(Len); inc(PByte(P)); if B<BEnd then continue; Flush; end else case c of 0: begin dec(B); break; end; 8: begin c := ord('b'); goto Esc; end; 9: begin c := ord('t'); goto Esc; end; $a: begin c := ord('n'); goto Esc; end; $c: begin c := ord('f'); goto Esc; end; $d: begin c := ord('r'); Esc: B^ := '\'; if B>=BEnd then // inlined: avoid endless loop Flush; B[1] := AnsiChar(c); inc(B); goto nxt; end; else begin // characters below ' ', #7 e.g. -> // 'u0007' B^ := '\'; AddShort('u00'); Add(HexChars[c shr 4],HexChars[c and $F]); goto nxt; end; end; until false; end;