16

显然||=行不通

def x?
  @x_query ||= expensive_way_to_calculate_x
end

因为如果结果是falseor nil,那么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除了false- 这一直追溯到https://rails.lighthouseapp.com/projects/8994/tickets/1830-railscachefetch-does-not-work-with-false-boolean -as-cached-value - 我向Andrew Marshall道歉,他给出了一个完全正确的答案。

4

2 回答 2

29

显式检查 的值@x_query是否nil改为:

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定义。但是,实例变量并非如此,因为它们默认为解析器在命中时没有定义它们。无论如何,我认为使用or的长块形式而不是单行with来保持一致是一个很好的习惯用法。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 回答