Rubyのプロックにおいて、表現の違い(proc / lambda)を整理する

## Procは処理の再利用には最高の構文

Rubyの特徴であり武器でもあるブロック。

このブロックを使い回すために、ブロックをオブジェクト化したProcを使いたいという場面はそこそこあります。

例えばRailsではscopeというmodelの機能にはProcが欠かせません。

```rb
class User
  scope :sign_in_more_than_n_times, ->(threshold){ where('sign_in_count > ?', threshold) }
end

User.sign_in_more_than_n_times(100)
#=> sing_in_countカラムが100を超えるユーザーのみ絞込

# この ->(threshold){ where('sign_in_count > ?', threshold) } の部分がまさにProcインスタンス.
```

## ただ生成方法が4つもある...
しかしそこでこまるのが、**プロックの表現多すぎる問題**。

この記事ではその違いをまとめたいと思います。

詳細は後述しますが（というかこの記事の本編ですが）、以下の記述は全て期待する挙動をします。

```rb
# Userモデルの各インスタンスがフォローしているユーザーの数を一覧で取得したい。
# 少々無理がある例かもしれないが勘弁願いたい

## 表現方法が4つもある
extract_followers_count_0 = Proc.new { |user| user.following_users.count }
extract_followers_count_1 = proc { |user| user.following_users.count }
extract_followers_count_2 = lambda { |user| user.following_users.count }
extract_followers_count_3 = ->(user) { user.following_users.count }

# 以下全て同じ結果になる
User.find_each.map(&:extract_followers_count_0)
User.find_each.map(&:extract_followers_count_1)
User.find_each.map(&:extract_followers_count_2)
User.find_each.map(&:extract_followers_count_3)
```

だいぶある...

## まずprocタイプとlambdaタイプに分けられることを理解する

といっても、上記4種類の表現方法は2つのタイプに分けられ、その違いだけをおさえておけばOKです

1.　procタイプ  

```rb
Proc.new { |var| puts var }
proc { |var| puts var } # procはProc.newの糖衣構文
```

2.　lambdaタイプ  

```rb
lambda { |var| puts var }
->(var){ puts var } # ->()はlambdaの糖衣構文
```

ではそれぞれの違いを見ていきましょう。

### 1. lambdaタイプのインスタンスはlambda属性を持っている
機能の違いに入る前に、Ruby内での識別の話から。
言葉の説明よりも以下のコードサンプルがわかりやすいかと思います。

```rb
# procタイプ
puts extract_followers_count_0 #=> #<Proc:0x007fd7822bdf48@(pry):28>
puts extract_followers_count_1 #=> #<Proc:0x007fd7822b5f00@(pry):29>
puts extract_followers_count_0.lambda? #=> false
puts extract_followers_count_1.lambda? #=> false

# lambdaタイプ
puts extract_followers_count_2 #=> #<Proc:0x007fd7822925c8@(pry):30 (lambda)>
puts extract_followers_count_3 #=> #<Proc:0x007fd78226e420@(pry):31 (lambda)>
                                                                    # ↑ココ!
puts extract_followers_count_2.lambda? #=> true
puts extract_followers_count_3.lambda? #=> true
```

### 2. lambdaタイプの方がよりメソッドに近い働きをする

さて、当記事のメインメッセージですが、両者の機能的な違いをおおまかにいうと**lambdaの方がよりメソッドに近い働きをする**という点があります。(と言ってもこれではまだよくわからない)

具体的には**引数の数不一致とブロック内returnの取り扱いが変わってくる**ところ。

```rb
# 1. 引数の挙動の違い
Proc.new { |var| puts var }.call(1, 2) #=> 1
lambda{|a| puts }.call(1, 2)  #=>  ArgumentError: wrong number of arguments (2 for 1)

# 2, return / break / nextの挙動の違い
def return_in_proc_break_outer_method
  Proc.new { return 100; puts :this_is_proc }.call # 外までは抜けない
  'proc'
end

def return_in_lambda_never_break_outer_method
  lambda { return 100; puts :this_is_lambda }.call # 外まで抜ける
  'lambda'
end

return_in_proc_break_outer_method 
#=> :this_is_proc 
# メソッドを抜けた

return_in_lambda_never_break_outer_method 
#=> 'lambda' 
# procの手続きだけ抜けた
```

returnのみならず、next / breakでの挙動の違いはRubyリファレンスの[こちら](http://docs.ruby-lang.org/ja/2.3.0/class/Proc.html)がわかりやすく整理されています


## まとめ
まとめとしては以下の二点を知っておくといいと思います。

1. **lambdaがメソッドに近い働きをする**。なので引数の数にはうるさいし、そとのメソッドまで抜けることはない
2. returnの挙動がややこしいのでproc, lambda内から抜けたい時はnextを使う。共にcallがある文脈に戻ってくる

以上です。

もろもろ誤りやアドバイスなどあればいただけますと幸いです