【Ruby入門】ProcとLambdaの違いまとめ【引数 return アロー】

【Ruby入門】ProcとLambdaの違いまとめ【引数 return アロー】

こんにちは!Webコーダー・プログラマーの貝原(@touhicomu)です。

今日は、RubyによるProc、lambdaの使い方と使い分けについて解説したいと思います。

この記事ではProc、lambdaの、

  • Procとlambdaの使い方
  • Procとlambdaへの引数の渡し方
  • Procをメソッドの引数に渡す方法

という基本的な内容から、

  • アロー演算子
  • クロージャー

などの応用的な使い方に関しても学習していきます。

このページで、RubyProc、lambdaの使い方をよく把握して自分のスキルとしていきましょう!

Procとlambdaの使い方と使い分け

Procとlambdaの使い方

Procは、defをインスタンスにしたもので、Proc.newメソッドによってdefのインスタンス変数を生成できます。

以上のように、インスタンス変数p1にProcオブジェクトを代入し、callメソッドにより、Proc.new時に定義したProcオブジェクトを呼び出すことができていますね。

Procオブジェクトはdefとほぼ同じです。

また、p1をp2に代入してp2から全く同じProcオブジェクトを呼び出すことができています。

対してlambdaはどうでしょう。

実は、lambdaはProc.newとほぼ同じ動作をします。

違いは、次節で解説します。

Procとlambdaの違い

lambdaは引数の数をチェックしている

lambdaは引数の数を文法チェックしています。

そのため、呼び出す時に引数の数が違うと、エラーとなります。

Procはdefと同じで、引数に値の指定がなかった場合はnilが引数に代入されます。

lambdaは、引数の数が違うと、(ArgumentError)を表示していますね。

returnするときの挙動が違う

Procとlambdaはreturn文の挙動が違います。

Procのreturnは、callの呼び出し元でreturnを実行したことと見なされます。

lambdaのreturnは、callの呼び出し先、つまりlambda自身のreturnであるものと見なされます。

proc_defでは、Procでreturnした時点で、proc_defが終了していますね。

対して、lambda_defでは、lambdaがreturnしても、lambda_defは処理を継続しています。

Procとlambdaへの引数の渡し方

渡すためのメソッド

Procとlambdaへの引数の渡し方にはいくつか種類のメソッドがあります。

それぞれProcとlambdaのインスタンスメソッドとなっています。

まずは、Procの例です。

次にlambdaの例です。

それぞれ、call()、[]、.()のインスタンスメソッドが定義されています。

基本的な渡し方

Procへの基本的な引数の渡し方として、

  • 配列引数の渡し方
  • デフォルト引数の渡し方
  • キーワード引数の渡し方

について学習していきましょう。

配列引数の渡し方

まずは、配列引数の渡し方

procのcall()メソッドに、複数の引数を与えた場合、受け取るprocの側では、それらの引数を配列として受け取ります。

注意点として、引数を受け取るproc側の引数名には「*(アスタリスク)」を明示的につけておかないといけない点です。

「*」をつけていない引数名、たとえば「arg」の場合、call()メソッドの第1引数のみ「arg」に入ります。

以下のサンプルコードでは、配列「args」に「each」メソッドを使用してループし、順に引数の順番と値をコンソールに出力しています。

実行結果:

実行結果が、「dump.call()」に渡した引数の順番と値に一致していますね。

Procの引数定義部(「|」から「|」内)に「*args」としていても、Proc内部では「args」だけで配列として使用できます。

デフォルト引数の渡し方

デフォルト引数とは、Procの呼び出し元の引数が省略されてProcが呼び出された際に使用される(デフォルトで決めてある)がある引数です。

呼び出し元で明示的に値が指定されている場合は、デフォルト値は使用されません。

デフォルト値は、以下の疑似コードのように指定します。

実際のサンプルコードをみていきましょう。

実行結果:

引数yや、z、を省略した場合、でデフォルト値が使用されています。

注意点として、デフォルト引数は引数記述部の右橋から順に指定する必要があります。

キーワード引数の渡し方

引数をキーワード引数とすることもできます。

キーワード引数には以下の特徴があります。

  • 指定する順番に依存しない
  • デフォルト値を指定できる
  • ハッシュを指定できる
  • ハッシュを渡すのと事実上同じ

以下、実際のサンプルコードをみていきましょう。

実行結果:

実行結果の1行目と2行目は、キーワード引数の省略がうまくできています。

2行目はキーワード引数が順番に依存しないことを示す例です。

3行目は存在しないキーワード名を与えるとunknown keywordエラーとなってしまう例です。

なおRubyのProcの引数に関して詳しくは、下記の記事を参照されてください。

【Ruby入門】引数の使い方まとめ【コマンドライン オプション】
更新日 : 2019年4月24日

応用的な渡し方

引数の数を示すarity

Procのarityメソッドは引数の数を返します。

実際のサンプルコードをみていきましょう。

なお、ここでは、Proc.newメソッドではなく、procキーワードでProc.newと等価なことを行っています。

また、procキーワードの書き方はlambdaキーワードの書き方と同じであることを把握しておいてください。

実行結果:

実行結果のように1行目と2行目は、引数の数を返しています。

3行目は、引数を「配列引数」と定義したため、「-1」となっています。

4行目は、「第1引数は通常の引数、それ以降は配列引数」と定義したため、「-2」となっています。

5行目は、引数を「キーワード引数」と定義したため、「0」となっています。

このように、メソッドが可変長引数を受け付ける場合、負の整数「-(必要とされる引数の数 + 1)」を返します。

引数情報を示すparameters

Procのparametersメソッドは、引数情報を返します。

この引数情報は以下の特徴があります。

  • 1引数あたり1個の配列で表されている
  • 全体の引数は配列で、複数の子配列をもつ親配列
  • 引数のタイプを示す情報は規定のシンボルになっている
  • 引数名はシンボルで表される

実行結果:

引数タイプを表すシンボルについては、以下のURLを参考にしてください。

instance method Method#parameters (Ruby 2.4.0)

Procをメソッドの引数に渡す方法

基本的な渡し方

Procは、「&」をつければ、ブロックとしてeachメソッドなどに渡せます。

以下では、配列のeachメソッドに対し、proc1に「&」をつけて渡しています。

実行結果:

eachでは1から5まで数え上げ、それぞれのループ中でproc1に引数(1から5までのループ変数値)と処理の制御を渡しています。

proc1では引数の2倍の数値をコンソールに出力しています。

応用的な渡し方

通常のメソッドにもProcに「&」をつけてブロックとして渡せます。

メソッド内では「yield n1, n2, … 」メソッドで引数n1、n2、・・・と引数を与えながら、制御をブロックに移せます。

以下の例ではProcを引数を1つ受け取るブロックとして渡す方法をサンプルコードで示します。

実行結果:

メソッドtestの「yield “hello”」にてブロック「&proc1」に対し引数「”hello”」を渡し制御をブロックに以降しています。

そして、「proc1」がコンソールに引数「”hello”」をpメソッドで出しています。

次にProcを引数を2つ受け取るブロックとして渡す方法をみていきましょう。

実行結果:

ブロックの引数が2個の場合でも、「yield」の引数を2個与えれば、OKであることがわかります。

Procとlambdaの応用

アロー演算子

Rubyにはlambdaと同等の機能を持つアロー演算子があります。

lambdaと同じく

  • defの引数
  • defのコード

を定義します。

->アロー演算子で、「lambda」キーワードと同等の機能を提供します。

(val)がアロー演算子での引数です。lambdaでは|val|でしたね。

{・・・}コード部です。

lambdaと同じく、アロー演算子でも引数の数をチェックしています。

クロージャー

クロージャーとは、Proclambdaの定義されているスコープ内で定義されている変数を、Procやlambda内でも使用できる機能のことです。

例えば、Procメソッドが定義されているdefメソッドのスコープ内の変数は、全てProcメソッドからアクセスできます。

lambdaでも、Procと同等のクロージャーが組めます。

まとめ

今回は、RubyProc、lambdaを学習しました!

学習のポイントを振り返ってみましょう!

  • Procとlambdaはほぼ同じ機能を持ち、関数を持ち歩ける
  • Procの引数の仕様はdefの引数と同じ
  • lambdaの引数の仕様はdefの引数とは違い厳しくチェックされる
  • arityで引数の数を、parametersで引数の情報を得られる
  • Procに「&」を付けるとメソッドにブロックとして渡せる
  • lamdaの簡略表現として「アロー演算子」がある
  • Proc、lambdaと同じスコープにある変数はProcからアクセスできる(クロージャー)

以上の内容を再確認し、ぜひ自分のプログラムに生かし学習を進めてください!

LINEで送る
Pocket

最短でエンジニアを目指すなら侍エンジニア塾

cta_under_bnr

侍エンジニア塾は業界で初めてマンツーマンレッスンを始めたプログラミングスクールです。これまでの指導実績は16,000名を超え、未経験から数多くのエンジニアを輩出しています。

あなたの目的に合わせてカリキュラムを作成し、現役エンジニア講師が専属であなたの学習をサポートするため効率よく学習を進めることができますよ。

無理な勧誘などは一切ありません。まずは無料体験レッスンを受講ください。

無料体験レッスンの詳細はこちら

書いた人

貝原 輝昌

貝原 輝昌

こんにちは!貝原(@touhicomu)と申します。
現在は、Web業界のフリーランスとして、主にPHP/WordPress/BuddyPress/VPSサーバー構築などの業務を受注しています。
現住所は、日本の西海岸、長崎県は波佐見町です。田舎ライフです。^^
地元の観光団体「笑楽井石」にボランティアでほたる撮影会やそば塾などのスタッフとして参加させて頂いています。
以下の活動も行っています。
 ・笑楽井石のブログ
 ・エクセル関数を日本語化するソフト
 ・エクセルVBAを日本語で記述するソフト

おすすめコンテンツ

あなたにぴったりなプログラミング学習プランを無料で診断!

プログラミング学習の効率を劇的に上げる学習メソッドを解説