【Ruby】メモ化とは?Rubyでの最適な方法を解説します

周りにRubyでのメモ化方法を知らない方がおられたので、改めて自分の理解を整理するためにもRubyでのメモ化についてまとめておきます。

対象読者
・メモ化が何かわからない人
・Rubyでのメモ化方法がわからない人
・いろんな方法があるけど、どの手法を用いたら良いかわからない人

メモ化とは?

実行結果を保持し、その結果を再利用する手法を「メモ化」と呼びます。

Rubyでよく見るメモ化

Rubyでのメモ化については、下3つの書き方を実際のプロダクトコードでよく見かけます。
(他にもメモ化の方法はありますが、代表的で現場で利用できるものだけ説明します。)

Rubyでよく見かけるメモ化の方法
# 自己代入
def hoge
   @hoge ||= hoge_func
end

# instance_variable_defined?
def foo
   return @foo if instance_variable_defined?(:@foo)
   @foo = foo_func
end

# defined?
def bar
   return @bar if defined?(:@bar)
   @bar = bar_func
end

Rubyでのメモ化について解説

自己代入 ||= を利用する

Rubyではnilとfalse以外は全て真として扱われます。
メモ化する式が真を返す場合には自己代入 ||= が使えます。

インスタンス変数の @hoge は未定義の時にnilを返すので、1回目の呼び出しでは hoge_funcの戻り値が@hogeに代入され@hogeが返却されます。

2回目以降は、@hogeは真であるため@hoge自信を返却します。

自己代入が分かりづらい方は以下のコードと捉えると理解しやすいと思います。

自己代入の分解
@hoge ||= 1
# 以下と同じ↓
@hoge || (@hoge = 1)

ただし、falsyな値(false, nil)が返却される場合は、自己代入だと毎回評価してしまい意味がありません。

自己代入は、式が真の時だけ有効な手段ということを覚えておいてください。

式が偽を返す場合は、次に解説する instance_variable_defined? または defined? を利用しましょう。

instance_variable_defined? もしくは defined? を利用する

自己代入 ||= は単なる論理和で、式が1回評価されたかは判断できません。

instance_variable_defined?、もしくはdefined?を使い、明示的にインスタンス変数の存在チェックをします。

これでnilやfalseを返す式もメモ化できます。

instance_valiable_defined?、defined?でのメモ化
# instance_variable_defined?
def foo
   return @foo if instance_variable_defined?(:@foo)
   @foo = foo_func
end

# defined?
def bar
   return @bar if defined?(:@bar)
   @bar = bar_func
end

instance_variable_defined?、defined? どちらを利用するかは好みに分かれます。

細かい話だと、defined?の方が最適化されているため処理速度が早いようですが、そこまで大きな差はないので、個人的には、意味が分かりやすい instance_variable_defined? を利用するのがオススメ。

まとめ

メモ化はパフォーマンス改善をする上で非常に便利な手法です。
何回も実行するけど、実行結果が変わらない処理は、積極的にメモ化を利用しましょう。

また、Rubyでのメモ化の際には、falsy値を考慮するため、instance_variable_defined? または defined? を利用が良さそうです。

是非、使い方をマスターして実際の開発に活かしてみてはいかがでしょうか。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です