16

明らか||=に動作しません

def x?
  @x_query ||= expensive_way_to_calculate_x
end

なぜなら、それがまたはであることが判明した場合falsenilそれexpensive_way_to_calculate_xは何度も何度も実行されるからです。

Array現在私が知っている最善の方法は、値を:に入れることです。

def x?
  return @x_query.first if @x_query.is_a?(Array)
  @x_query = [expensive_way_to_calculate_x]
  @x_query.first
end

これを行うためのより従来的または効率的な方法はありますか?

更新私はメモ化したいと思いnilました-これはhttps://rails.lighthouseapp.com/projects/8994/tickets/1830-railscachefetch-does-not-work-with-false-booleanfalseにまでさかのぼります-as-cached-value-それ以外の点では完全に正しい答えを与えてくれたAndrewMarshallに謝罪します。

4

2 に答える 2

29

の値@x_querynil代わりにあるかどうかを明示的に確認します。

def x?
  @x_query = expensive_way_to_calculate_x if @x_query.nil?
  @x_query
end

これがインスタンス変数でない場合は、すべてのインスタンス変数がデフォルトでに設定されているため、これも/代わりに定義されているかどうかを確認する必要があることに注意してくださいnil

@x_queryのメモ化された値がである可能性がある更新を考えると、代わりに、すべてのインスタンス変数がデフォルトで次のようになるという事実を回避するためにnil使用できます。defined?nil

def x?
  defined?(@x_query) or @x_query = expensive_way_to_calculate_x
  @x_query
end

a = 42 unless defined?(a)パーサーがヒットすると、条件に達するa =aが定義されるため、のようなことを行うと期待どおりに機能しないことに注意してください。ただし、インスタンス変数はデフォルトでパーサーにヒットしたときに定義されないため、これは当てはまりません。とにかく、一貫性を保つために、1行の代わりにまたはの長いブロック形式を使用するのは良いイディオムだと思います。nil=orunlessunlessdefined?

于 2012-06-22T15:13:40.167 に答える
23

を説明するにはnil、を使用defined?して変数が定義されているかどうかを確認します。

def x?
  return @x_query if defined? @x_query
  @x_query = expensive_way_to_calculate_x
end

defined?nil変数が定義されていない場合は戻り、"instance_variable"そうでない場合は文字列が返されます。

irb(main):001:0> defined? @x
=> nil
irb(main):002:0> @x = 3
=> 3
irb(main):003:0> defined? @x
=> "instance-variable"
于 2012-06-22T20:57:35.167 に答える