VB のたまご

作成日: 2015/12/03, 更新日: 2015/12/03


ラムダ式を学んで、1つ上のプログラミングをしよう

作業用メソッドの煩雑さ

  •  最近プログラムを組んでいる時に、メイン処理に対して、共通化できそうな処理のまとまりや、長くなりそうな処理のまとまりを、 作業用メソッドとしてメイン処理の外に出して、呼び出して使うようになりました。

  • スポンサーリンク


    Console.WriteLine("3+2={0}", 3 + 2)
    Console.WriteLine("3-2={0}", 3 - 2)
    Console.WriteLine("3x2={0}", 3 * 2)
    
  •  このようなサンプルは、ちょっと極端すぎる例ですが、プログラミングの最初は、要求に従ってガリガリと処理を書いていきます。 一通り終わった後で、表示部分と計算部分が混ざっていることが気になりはじめ、計算部分は別枠として共通メソッド化すれば、 今後、他からも呼び出して使えるなぁとか、そうすることで、表示部分と計算部分を処理分割出来て、 シンプルに分かりやすく、見やすくなるなぁ、等と、勝手に考えが進んでいく感じになります。

  • Console.WriteLine("3+2={0}", Me.Plus(3, 2))
    Console.WriteLine("3-2={0}", Me.Minus(3, 2))
    Console.WriteLine("3x2={0}", Me.Multi(3, 2))
            
    Private Function Plus(i1 As Integer, i2 As Integer) As Integer
        Return i1 + i2
    End Function
    
    Private Function Minus(i1 As Integer, i2 As Integer) As Integer
        Return i1 - i2
    End Function
    
    Private Function Multi(i1 As Integer, i2 As Integer) As Integer
        Return i1 * i2
    End Function
    
  •  あれこれ浮かんできたもので、このように直したとします。 ここでもまた、あらためて見返してみると冗長すぎるかなぁとか、こういうことは、他からも呼び出す必要が実際に出てから、共通化を考えるべきかなぁとか、 あれこれ考えてしまいます。実際のプロダクトコードの場合、テスト工程もあるのでどうしよどうしよと迷います。 とりかえず、ここで考え出すと無限ループになってしまうので、置いておきます。

  •  仮に、よその処理ではまず使わないなと、この処理内でしかこの先も使わないなという状況の場合(多分レベルでもOK、直感で感じた場合)、 何とか処理を短くしたいと思うわけです。できるだけメソッドの中で完結したい、必要な範囲を狭めたい、スクロールして行ったり来たりしたくないなぁ、 と思うわけです。作業用メソッドが増えれば増えるほど、呼び出し側のメソッドと、定義側のメソッドが離れていく、あの状態が嫌なんです。見づらいから。

スポンサーリンク


ラムダ、やべー

  •  このような時には、VB2008 から登場して、VB2010 で強化された、ラムダ式を使うことで解決することができます。

  • Dim plus = Function(i1 As Integer, i2 As Integer) i1 + i2
    Dim minus = Function(i1 As Integer, i2 As Integer) i1 - i2
    Dim multi = Function(i1 As Integer, i2 As Integer) i1 * i2
    
    Console.WriteLine("3+2={0}", plus(3, 2))
    Console.WriteLine("3-2={0}", minus(3, 2))
    Console.WriteLine("3x2={0}", multi(3, 2))
    
  •  これがラムダ式に書き直したものです。ラムダ式とは、名前の無いメソッドのことで、変数にセットして使います。 デリゲートのような扱い方です。変数のように、そのメソッド内だけで、一時的にしか使わないメソッドに適しています。

  •  ちらっと出てきましたが、ラムダ式がメソッドであるということは、デリゲートに渡せるということです。 (ジェネリックについてはこちら、デリゲートについてはこちらを参照ください)。 ラムダ式をデリゲートにセットする際には、ジェネリックデリゲートを使います。
  • Dim multi2 As New Func(Of Integer, Integer, Integer)(Function(i1, i2) i1 * i2)
    Console.WriteLine("3x2={0}", multi2(3, 2))
    

  •  この、「ジェネリックデリゲート+ラムダ式」という組み合わせは、LINQ を扱う上で重要な事なので、できるだけ使い慣れてほしいなと思います。 最後に、単一行や複数行で、戻り値無しラムダ式、戻り値ありラムダ式のサンプルを確認します。



  • 単一行、戻り値無しのジェネリックデリゲート+ラムダ式
  • Dim m1 As New Action(Of String)(Sub(s As String) Console.WriteLine(s))
    m1("method1")
    
    ' 出力結果
    method1
    

  • 複数行、戻り値無しのジェネリックデリゲート+ラムダ式
  • Dim m2 As New Action(Of String)(Sub(s As String)
                                        s = ControlChars.Quote & s & ControlChars.Quote
                                        Console.WriteLine(s)
                                    End Sub)
    m2("method2")
    
    ' 出力結果
    "method2"
    

  • 単一行、戻り値ありのジェネリックデリゲート+ラムダ式
  • Dim m3 As New Func(Of Integer, Integer)(Function(i As Integer) i * i)
    Dim i1 As Integer = m3(3)
    Console.WriteLine(i1)
    
    ' 出力結果
    9
    

  • 複数行、戻り値ありのジェネリックデリゲート+ラムダ式
  • Dim m4 As New Func(Of Integer, Integer)(Function(i As Integer)
                                                Return i * i * i
                                            End Function)
    i1 = m4(3)
    Console.WriteLine(i1)
    
    ' 出力結果
    27
    
  •  ちょっとわかりづらいかなというところは、戻り値ありのジェネリックデリゲートの定義です。一番後ろの型指定は「戻り値」の型を指定します。 つまり、引数が1つで Integer 型、戻り値が Integer 型の場合は、Func(Of Integer, Integer) となります。 引数が2つで Integer 型、戻り値が Integer 型の場合は、Func(Of Integer, Integer, Integer ) となります。 また、戻り値ありのラムダ式についても、単一行の場合、Return キーワードが省略されます。Return キーワードを書くと逆に構文エラーです。 しかし、複数行の場合は、Return キーワードを書かないと構文エラーですので、気を付けてください。と言っても、書いたらすぐにエラーで教えてくれるので大丈夫です。

  •  本記事内ではうまく書けませんでしたが、使いこなすと、びっくりするぐらいソースコードが綺麗にスッキリします。 メソッドをインラインで表せるということはすごい可能性を秘めています。

  •  最後までこの記事を読んでいただき、ありがとうございました。

  • スポンサーリンク