LoginSignup
icoke
@icoke

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

for文の初期化部で宣言した変数のスコープが終わる前に終了時処理を挟みたい

for文の初期化部で宣言した変数のスコープが終わる前に終了時処理を挟みたい

タイトル文の通りですが、for文に終了時処理を挟むきれいなやり方って何でしょうか?
例えば配列を操作する処理を行うときに、終端にだけ特別な処理を行いたいときとかあるじゃないですか。
実直に実装するなら、

for ( int i = 0; true; i++ ) {
    if ( i == N ) {
        // 終了時処理
        break;
    }
    // ループ処理
}
// または
for ( int i = 0; true; i++ ) {
    if ( i < N ) {
        // ループ処理
    } else {
        //終了時処理
        break;
    }
}
// この例は条件式が i < N なので、例えば arr[N - 1] = M; とかできますが、それはなしで

となるんでしょうけど、せっかくfor(初期化;条件式;変化式)で実装されてあるのにそれをtrueにして、ループが終了する条件をfor()文内に書いてるのも気持ち悪いです。
while(true)は感情的に許せるのですがwhile文を使おうとするならint iのスコープが外にまで出てしまうので、

if ( true ) {
    int i = 0;
    while ( i < N ) {
        // ループ処理
    }
    // 終了時処理
}

と無駄なif(true)でスコープを指定しないといけないのがまた、気持ち悪いです。

というのも最近、try, catch, finallyの例外処理というものを知って、それが出来るならfor()にもfinallyみたいなのが欲しいと思ったのです。
理想としては、

for ( int i = 0; i < N ; i++ ) {
    // ループ処理
} finally {
    // 終了処理
}

みたいな感じです。

なにかいい方法はありませんか?
C#以外でもいいです。皆さんの意見よろしくお願いします。

P.S.
Pythonだとあるみたいですね...。なんでc#にはないんだ。

0

3Answer

最後かどうかとるのは面倒くさい扱いなので
foreach にして ValueTuple で渡しがちですね。

using System;
using System.Linq;

var count = 11;
var start = 0;
foreach (var (n, isLast) 
 in Enumerable.Range(start, count).Select((n,index) => (n, index + 1 >= count)))
{
    Console.WriteLine($"n:{n,2}, isLast:{isLast}");
}

sharplab

output
n: 0, isLast:False
n: 1, isLast:False
n: 2, isLast:False
n: 3, isLast:False
n: 4, isLast:False
n: 5, isLast:False
n: 6, isLast:False
n: 7, isLast:False
n: 8, isLast:False
n: 9, isLast:False
n:10, isLast:True
2

と無駄なif(true)でスコープを指定しないといけないのがまた、気持ち悪いです。

ブロックスコープなら if 書かなくてもいいのでは?

{
   // ブロックスコープ
}
1

Comments

  1. @icoke

    Questioner

    そういう書き方ってできるんですか?
    前、なにかのサンプルコードで

    do {
    } while ( false )
    

    で挟んでブロックする方法見て、勝手にできないと思ってました。

  2. @icoke

    Questioner
    {
        int i = 0;
        while ( i < 10 ) {
            i++;
        }
        Debug.WriteLine(i);
    }
    {
        int i = 2;
        Debug.WriteLine(i);
    }
    

    でテストしてみたんですがいい感じですね。参考になりました。ありがとうございます。

  3. C や C++ でマクロとして定義するときに単なるブロックで書いてしまうとマクロ展開後に前後の字句と組み合わさって変な結果になることがあります。 それを避けるためにマクロ定義中で複数の文をまとめるときは do/while で囲む方法がイディオムとして確立しています。 (ifwhile でも不都合があります。) C/C++ のマクロに特有の事情です。

    他の言語で事情を考えずに真似をしたコードを書いてしまった人がいたのかもしれません。

  4. @icoke

    Questioner

    そんな事情があったんですね。初めて知りました。参考になります。

Your answer might help someone💌