Webサイト制作コースのお申し込みはこちら Webサイト制作コースのお申し込みはこちら

まずはブロックを理解しよう

Procクラスを理解するには、Rubyのブロックを知っておく必要があるため、まずはブロックについてから解説していきます。

ブロックとは、引数と一緒に渡すことのできる処理のかたまりです。eachメソッドなどの繰り返しで使用されることが多いため、繰返し処理の中で行われる処理というイメージがあるかもしれませんが、それはブロックの1つの使い方であって、厳密にはdo~end{}で囲また処理をブロックと呼びます。

ブロックの使い方

ブロックの使い方を見ていきましょう。

Rubyのブロックには、do~endで処理を書く方法と{}で囲まれた中に処理を書く方法の2つの書き方が存在します。

do~endで書くブロック

(1..10).each do |i| 
  puts i
end

{}(中括弧)で書くブロック

(1..10).each { |i| puts i }

どちらの書き方でもブロックであり、機能としては同じであるため、好みによってどちらを使っても構いません。ただし、一般的には処理が複数行に渡る場合はdo~endで書き、処理が1行で済む場合は{}で囲う書き方を用います。

ブロックはファイル入出力でも使用

Rubyのブロックは、ファイルの入出力処理でも使います。

File.openメソッドでファイルを開き、ブロックで開いたファイルに対する入出力の処理を定義します。そしてブロックを抜けるとファイルが自動でクローズされるため、閉じ忘れもなく処理を行えます。

File.open("qiita_todo_with_block.txt", "w") do |f|
 f << "1行目の書き込み内容\n"
 f << "2行目の書き込み内容\n"
end

ブロックを引数で渡す

ブロックをメソッドの引数として受け取り、渡されたブロックを実行するメソッドを定義できます。

このようなメソッドを作ることで、メソッドの一部の処理を引数で受けとったブロックの処理で置き換えることが可能になり、ある部分までは共通化された処理で、一部だけ機能によって処理が異なる部分のメソッドを共通化しやすくなります。

次のサンプルコードは、引数で渡されたブロックを10回実行して、その合計値を返すメソッドを定義する例です。

def total()
    result = 0
    for num in 1..10 
        if block_given?
            #ブロックが引数で渡されたとき 
            result += yield(num)
        else
            #ブロックが渡されなかったときのデフォルトの処理
            result += num
        end
    end
    return result
end

puts "ブロックを引数で指定"
puts total() {|num| num ** 2}

puts "ブロックを省略"
puts total()
実行結果
-------------------
ブロックを引数で指定
385
ブロックを省略
55

このように、ブロックを受け取るメソッドではblock_given?でブロックが指定されているか判定し、ブロックの指定が省略された場合は、デフォルトの処理を通すようにするのが一般的です。

Procとは

それでは、本題のProcについて触れていきましょう。

Procとは「ブロックをオブジェクト化したProcクラスのインスタンス」です。
前章で解説したブロックを、ローカル変数のスコープやスタックフレームと共にオブジェクト化し、ブロックの代わりにメソッドの引数に渡すことができます。

ブロックはその特性上、メソッドの引数に1つしか指定することができませんが、Procにオブジェクト化したブロックであれば、通常の変数と同じようにメソッドで複数渡すことも可能です。

Procの作り方

Procオブジェクトは、次の3つの方法で作ることができ、作成したProcオブジェクトのcallメソッドより、指定したブロックの処理を実行することができます。

1) procキーワードでブロックをProcオブジェクトに変換

my_proc = proc { |n| n * 2 }
my_proc.call(2) #=> 4

2) Procクラスのコンストラクタにブロックを指定してProcオブジェクトを作成

my_proc = Proc.new { |n| n * 2 }
my_proc.call(2) #=> 4

3) メソッドの引数として渡す

def sample_proc(&my_proc)
  puts my_proc.call(2)  #=> 4
end
sample_proc { |n| n * 2 }

「&引数名」のようにメソッドの引数を宣言すると、呼び出し元で指定されたブロックがProcオブジェクトに変換され、メソッドの中で引数として渡されたブロックをcallメソッドで呼び出すことができます。

複数のProcをメソッドの引数として渡す

Procはブロックをオブジェクト化したものであるため、他の数値や文字などの変数と同じ扱いになり、メソッドの引数としても複数渡せます。

次のサンプルコードは、引数を2倍と3倍にするProcオブジェクトを2つ用意して、メソッドの引数として渡し、呼び出し先のメソッド内で2つのProcオブジェクトの処理をそれぞれ実行する例です。

#複数のProcを受け取るメソッド
def sample_proc2(p1, p2)
  puts p1.call(2)
  puts p2.call(2)
end

#引数を2倍と3倍にして返すProcをそれぞれ定義
my_proc1 = proc { |n| n * 2 }
my_proc2 = proc { |n| n * 3 }

#メソッドの引数に複数のProcを渡す
sample_proc2(my_proc1, my_proc2)
実行結果
-------------------
4
6

Procとlambda

lambdaは、Procオブジェクトを作るもう一つの方法ですが、procキーワードや、Proc.newで作成したProcオブジェクトとで、returnの挙動が異なります。

Proc.newでreturnした時

Proc.newprocキーワードで作成したProcオブジェクトは、そのブロック内でreturnをすると、呼び出し元のメソッドから抜けてしまいます。

def sample1
  proc1 = Proc.new { return p "proc" }
  proc1.call
  p "proc1#call実行後の処理"
end

sample1
実行結果
-------------------
proc
ポテパンダの一言メモ

Proc.newprocキーワードで作成したProcオブジェクトでreturnをする時、callメソッドを呼んだメソッドを抜けるわけではなく、そのProcを宣言したメソッドから処理が抜けることに注意が必要です。

lambdaでreturnした時

一方、lambdaで作成したProcオブジェクトは、そのブロック内でreturnをしても、呼び出ししたメソッドの処理に戻り、後続の処理が実行されます。

def sample1
  lambda1 = lambda { return p "lambda" }
  lambda1.call
  p "lambda1#call実行後の処理"
end

sample1
実行結果
-------------------
lambda
lambda1#call実行後の処理

まとめ

RubyのブロックとProcクラスについて解説してきました。ブロックの概念は最初は難しいかもしれませんが、Rubyを学ぶ上では避けてわ通りない道ですので是非理解しておきましょう。

【関連記事】
Rubyのlambdaとは?ブロックの使い方から詳しく解説

エンジニアになりたい人に選ばれるプログラミングスクール「ポテパンキャンプ 」

ポテパンキャンプは卒業生の多くがWebエンジニアとして活躍している実践型プログラミングスクールです。 1000名以上が受講しており、その多くが上場企業、ベンチャー企業のWebエンジニアとして活躍しています。

基礎的な学習だけで満足せず、実際にプログラミングを覚えて実践で使えるレベルまで学習したいという方に人気です。 プログラミングを学習し実践で使うには様々な要素が必要です。

それがマルっと詰まっているポテパンキャンプでプログラミングを学習してみませんか?

卒業生の多くがWebエンジニアとして活躍

卒業生の多くがWeb企業で活躍しております。
実践的なカリキュラムをこなしているからこそ現場でも戦力となっております。
活躍する卒業生のインタビューもございますので是非御覧ください。

経験豊富なエンジニア陣が直接指導

実践的なカリキュラムと経験豊富なエンジニアが直接指導にあたります。
有名企業のエンジニアも多数在籍し品質高いWebアプリケーションを作れるようサポートします。

満足度高くコスパの高いプログラミングスクール「ポテパンキャンプ」

運営する株式会社ポテパンは10,000人以上のエンジニアのキャリアサポートを行ってきております。
そのノウハウを活かして実践的なカリキュラムを随時アップデートしております。

代表の宮崎もプログラミングを覚えサイトを作りポテパンを創業しました。
本気でプログラミングを身につけたいという方にコスパ良く受講していただきたいと思っておりますので、気になる方はぜひスクール詳細をのぞいてくださいませ。