条件によって関数の頭からやり直す方法について


  2009-04-02 23:00:08  No: 33859

関数のなかで何個か条件式があるとします。
条件によっては関数の頭からやり直したいのですが、gotoや再帰呼び出しはしたくありません。
方法としては無限ループで全体をくくってContinueが一番良い方法なのでしょうか?
ほかになにか良い方法はありますか?

よろしくお願いします。


monaa  2009-04-02 23:21:55  No: 33860

自分を呼び出すのはどうでしょうか。
呼び出しすぎるとオーバーフローしますが。
それがだめなら独自メッセージをアプリケーションに送るとか、
ちょっと大がかりになります。
他にも方法あるんすかね?

procedure Get00;
var
  c:Cardinal;
begin
  c:=GetTickCount;
  if c mod 100 <> 0 then
  begin
    sleep(1);
    Get00;
    Exit;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  c:Cardinal;
begin
  Get00;
  //下二桁を00にする
  Caption:= inttostr(GetTickCount);
end;


monaa  2009-04-02 23:23:39  No: 33861

失礼!再帰呼び出しです;;
うー消したい;;


  2009-04-02 23:57:07  No: 33862

そもそも再帰呼び出しは、オーバーフローなど(他にどういった懸念があるかわかりませんが)当時からあまり使いたくないものだと自分のなかで認識してきました。
しかし結果的にGotoや無限ループで条件から抜けれなかったりすれば同じようにオーバーフローしてしまうんですよね?
そう考えると結局今回の私のケース:「条件によって頭からやり直す」だとどれも変わらない気がしてきましたが、認識はあってますでしょうか?

今回の私のケース:「条件によって頭からやり直す」以外の場合で考えますと、Gotoは条件によっては好きなところに飛ぶことができて便利ですが、あまり使われないし、嫌う人が多いです。見づらくなってしまうといいますがなんかほかに危ないこととかあるんですかね?


通りすがり  2009-04-03 01:09:39  No: 33863

goto文は嫌われ?ものですが、私は個人的には嫌いではないです。

妙に複雑なcontinueやフラグを立てて理解し難くするよりは
よっぽど流れがわかりやすいように思います。
(..と言いながら、過去2〜3回しか使った事はありませんが)

理想を追求して複雑にするよりもわかり易いソースの方が
後のメンテの為にも良いように思いますが...
(勿論いつでも使うと言うより必要に応じてと言うことで)


monaa  2009-04-03 01:15:15  No: 33864

Gotoや無限ループはその中でメモリの確保、解放が正しく行われていれば
オーバーフローしませんよ。
カウンタなんかをつけると桁あふれを起こしたりはしますが。
さっきの私の例は関数の終了前に関数を呼び出すので、
スタックがどんどん積み重ねられます。
例の内容は不適切ですが、再帰処理のほうが都合がいい場合も多々ありますんで。
目的に合わせてお使いください。


tor  2009-04-03 01:24:14  No: 33865

> しかし結果的にGotoや無限ループで条件から抜けれなかったりすれば同じようにオーバーフローしてしまうんですよね?
それはオーバーフローではなくフリーズと表現すべきかと。
再起呼び出しだと、比較的少ない有限の回数でもオーバーフローを引き起こす可能性のあるところが問題でしょうね。

本当に頭からやり直したいのだとすれば、構造化プログラミングの枠組みでは
- ループの中に入れる
- 上位の関数から、条件を満たすまで繰り返し関数を呼び出す
あたりが落としどころでしょう。
「やり直したい」ケースがあるということはつまり「条件を満たすまでやり直す」必要があるということですから、ループになるのは自然だと思えますが。

どちらも嫌なら、ロジックを見直して先頭に戻る必要がないようにするしかないですね。
やりたいことが具体的にわからないと何とも言えませんが、たとえば
「条件を整える部分」と「本体の処理」の二つに分割できないんでしょうか?


  2009-04-03 01:43:10  No: 33866

私はオーバーフローを勘違いしてますね。
関数が呼ばれるごとにスタックに関数が積み上げられるんですよね。
関数が終わる前に自身を呼び出して、それが終了条件を満たさないとどんどん積みあがってそれがスタックオーバーフローになってしまうんですよね?

だからGotoや無限ループの場合はtorさんがいっている通り、フリーズという表現になりますね。

という認識であっていますか?
初心者ですいません。

さて、本題ですが、通りすがりさんが言うように私もでかい枠組みでループを使用するわかりづらさよりはGOTOのほうが見やすいと思っています。
ただ今回はそんなに長いプログラムではないのでループで囲んじゃおうと思いますが…。

ただ長いプログラムであればtorさんがいっている通り、「条件を整える部分」と「本体の処理」の二つに分割が一番すっきりしますね。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加