はじめに
Proc
って知ってますか?僕は知らないです。
scope :old, -> { where('year_published < ?', 50.years.ago )}
Railsだと、上記のようにmodel
にscope
を定義したりしますが、これはlambda
によってProc
オブジェクトが生成されています。
Railsを触っているとProc
にはちょくちょく出会うので、出会った時にビビらないようにまとめたいと思います。
Procとは
ブロックをコンテキスト(ローカル変数のスコープやスタックフレーム)とともにオブジェクト化した手続きオブジェクトです。
らしいです。処理自体をオブジェクトにすることができます。
ProcはProcedureを意味しています。
square = Proc.new{|a| a ** 2}
square.call(8) # => 64
例えば上記のような例を考えた場合、変数square
にはa(引数)を二乗する
という処理が入ります。
呼び出したい時はcallメソッド
を使うことで呼び出すことができます。
Procオブジェクトの作り方
proc1 = Proc.new{|x| x * 2}
# => #<Proc:0x00000001076f1af0 (irb):24>
proc2 = proc {|x| x * 2}
# => #<Proc:0x0000000107620568 (irb):25>
proc3 = lambda{|x| x * 2}
# => #<Proc:0x0000000107182678 (irb):26 (lambda)>
proc4 = -> (x) { x * 2}
# => #<Proc:0x0000000102e1f7a0 (irb):27 (lambda)>
↓ lambda
によって生成した場合のProc
オブジェクトの性質は少し異なります。
- In lambdas, return and break means exit from this lambda;
- In non-lambda procs, return means exit from embracing method (and will throw LocalJumpError if invoked outside the method);
- In non-lambda procs, break means exit from the method which the block given for. (and will throw LocalJumpError if invoked after the method returns);
- In lambdas, arguments are treated in the same way as in methods: strict, with ArgumentError for mismatching argument number, and no additional argument processing;
- Regular procs accept arguments more generously: missing arguments are filled with nil, single Array arguments are deconstructed if the proc has multiple arguments, and there is no error raised on extra arguments.
メソッドとの違い
メソッドとの大きな違いは、Proc
はObject
にバインドされていないところだと思います。
Ruby
は第一級関数を持たず、関数をデータとして扱いません。
そのため、メソッドには必ずレシーバがあり、なんらかのObject
にバインドされています。
一方でProc
の場合は、レシーバを必要としないため第一級関数のように使うことができます。
[1] pry(main)> def hello
[1] pry(main)* puts "hello"
[1] pry(main)* end
# => :hello
[2] pry(main)> method(:hello).receiver
# => main
[3] pry(main)> hello_proc = Proc.new{puts "hello"}
# => #<Proc:0x0000000109a9dda0 (pry):6>
[4] pry(main)> hello_proc.receiver
# NoMethodError: undefined method `receiver' for #<Proc:0x0000000109a9dda0 (pry):6>
参考にしたサイト