2020年10月7日水曜日

Ruby の lambda 使い方メモ

概要

lambda や Proc の使い方をメモがてら紹介します

環境

  • macOS 10.15.7
  • Ruby 2.7.1p83

lambda を使って Proc オブジェクトを作成する

まずは基本中の基本です
lambda メソッドにブロックを渡すと Proc オブジェクトが返ってきます
それを変数に格納してあとから call メソッドを呼び出すことでブロックに定義した処理を実行することができます

my_lambda = lambda do
  puts 'ok'
end

puts my_lambda1.class
my_lambda.call

引数付きの lambda

lambda には引数を与えることもできます
ブロックを定義する際にブロック引数を与えることで call 時に引数を与えることができます

my_lambda = lambda do |val|
  puts val
end

my_lambda.call('hello')

作成した Proc オブジェクトをメソッドに与える

Proc オブジェクトを引数としてメソッドに渡すこともできます
受け取るメソッドは &block という感じで Proc オブジェクトを受け取れるようにするだけです

my_lambda = lambda do |val|
  puts val
end

def test_lambda_arg(val, &block)
  block.call(val)
  # yield(val)
end

test_lambda_arg('hello', &my_lambda)

メソッドに Proc オブジェクトを渡す場合は & を付与してブロックとして渡します
メソッドは受け取った Proc オブジェクトに対して call メソッドを呼び出すだけです
また別の呼び方として受け取った Proc オブジェクトを yield とするだけでも呼び出すことができます (更に言うと引数の &block も省略できます、ここでは紹介しないので詳しくはこちらなどを参照してください)

クラスのインスタンス変数として Proc オブジェクトを管理する

Proc オブジェクトは当然インスタンス変数としても管理できます
先程紹介したように yield を使うこともできます

class Test
  def initialize(&block)
    @block = block
  end

  def my_call(val)
    @block.call(val)
  end
end

my_lambda = lambda do |val|
  puts val
end

t = Test.new(&my_lambda)
t.my_call('hello')

initialize に Proc オブジェクトを渡す

応用テクニックの一つとして initialize に Proc オブジェクトを渡すことでインスタンス変数の初期化などを行うこともできます

class Test
  attr_accessor :val1, :val2

  def initialize(&block)
    block.call(self)
  end

  def print()
    puts @val1
    puts @val2
  end
end

t = Test.new do |obj|
  obj.val1 = 'val1'
  obj.val2 = 'val2'
end
t.print

クラス側ではブロックで初期化されるであろうインスタンス変数を attr_accessor で事前に定義しておく必要がります
また initialize 内では引数として受け取った Proc オブジェクトに self を与えることで自信のクラスのインスタンス変数を参照できるようにします

initialize に引数をわざわざ追加する必要がなくなるのでコードの修正が小さくなるのがメリットかなと思います

最後に

lambda と Proc オブジェクトの基本的な使い方を紹介しました
これ以外にもスコープの話などのあるので詳しくは参考サイトにある公式のドキュメントが参考になると思います

参考サイト

0 件のコメント:

コメントを投稿