コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

Railsでインスタンス変数に代入することをメモ化と呼ぶのは趣の違う話なのでざっくりまとめる

表題通り違和感をまとめる。

前提としてメモ化とは

Wikipedia曰く以下の通り

メモ化(英: Memoization)とは、プログラムの高速化のための最適化技法の一種であり、サブルーチン呼び出しの結果を後で再利用するために保持し、そのサブルーチン(関数)の呼び出し毎の再計算を防ぐ手法である。 (中略) メモ化された関数は、以前の呼び出しの際の結果をそのときの引数と共に記憶しておき、後で同じ引数で呼び出されたとき、計算せずにその格納されている結果を返す。メモ化可能な関数は参照透過性を備えたものに限られる。すなわち、メモ化されたことで副作用が生じない場合に限られる。 - メモ化 - Wikipedia

ということでメソッドや関数において、同一の引数の場合は再計算せず保存した値を出すことで速度を稼ぐ手法。

Rubyの簡単な例

フィボナッチ数列の例が多いのでそれを題材とする、まずはメモ化しない例

class CalcFibonacci
  # フィボナッチ数列は1個前と2個前の合計値
  def fibonacci(n)
    # 0と1は前がないので
    if n <= 1
      n
    else
      fibonacci(n-1) + fibonacci(n-2)
    end
  end
end

これを計算結果をmemorizeすると以下

class CalcFibonacci
  def initialize
    @cache = {}
  end

  def fibonacci_with_memorize(n)
    # すでに計算済みであれば返却
    return @cache[n] if @cache.has_key?(n)
    if n <= 1
      result = n
    else
      result = fibonacci_with_memorize(n-1) + fibonacci_with_memorize(n-2)
    end

    @cache[n] ||= result
    result

  end
end

メモ化することで再計算がされなくて済む

メモ化のようでメモ化ではない例

Railsにおいて以下の動作がメモ化の例として取り上げられることがある。

def user
  @user ||= User.find(params[:id])
end

一見メモ化のように見えるが、メモ化は以下の通りなので趣が違う。

メモ化された関数は、以前の呼び出しの際の結果をそのときの引数と共に記憶しておき、後で同じ引数で呼び出されたとき、計算せずにその格納されている結果を返す。

これはparamsの値を使っている時点でクラスの状態に左右されるため、引数の値を使うという部分でことなる。そのため上記のようなRailsの例はメモ化というよりはDB読み込みのキャッシュとなる。

参考リンク