显然||=
无效
def x?
@x_query ||= expensive_way_to_calculate_x
end
因为如果结果是false
或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 - 我向{{向{{}}道歉3}}谁给出了一个完全正确的答案。
答案 0 :(得分:26)
明确检查@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 =
,{<1}}就会在到达条件之前定义。但是,实例变量不是这样,因为它们默认为a
,解析器在命中nil
时不会定义它们。无论如何,我认为使用=
或or
的长块形式而不是带unless
的单行unless
来保持一致是一个很好的习惯。
答案 1 :(得分:21)
要考虑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"