1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

はじめに

Procって知ってますか?僕は知らないです。

    scope :old, -> { where('year_published < ?', 50.years.ago )}

Railsだと、上記のようにmodelscopeを定義したりしますが、これはlambdaによってProcオブジェクトが生成されています。
Railsを触っているとProcにはちょくちょく出会うので、出会った時にビビらないようにまとめたいと思います。

Procとは

ブロックをコンテキスト(ローカル変数のスコープやスタックフレーム)とともにオブジェクト化した手続きオブジェクトです。

らしいです。処理自体をオブジェクトにすることができます。

ProcProcedureを意味しています。

    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.

メソッドとの違い

メソッドとの大きな違いは、ProcObjectにバインドされていないところだと思います。

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>

参考にしたサイト

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?