如何在Ruby中记忆可能返回true,false或nil的方法?
显然||=
不会起作用
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
有更传统或更有效的方法吗?
更新我意识到我想记住除了false
nil
之外 – 这一直回到https://rails.lighthouseapp.com/projects/8994/tickets/1830-railscachefetch-does-not-work-with-false -boolean-as-cached-value – 我对Andrew Marshall道歉,他给出了一个完全正确的答案。
明确检查@x_query
的值@x_query
为nil
:
def x? @x_query = expensive_way_to_calculate_x if @x_query.nil? @x_query end
请注意,如果这不是实例变量,则必须检查它是否也被定义,因为所有实例变量都默认为nil
。
鉴于您的更新, @x_query
的memoized值可以为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 = 42 unless defined?(a)
东西a = 42 unless defined?(a)
将无法按预期工作,因为一旦解析器命中a =
, a
就会在达到条件之前定义。 但是,实例变量不是这样,因为它们默认为nil
,当它命中=
时,解析器不会定义它们。 无论如何,我认为这是一个很好的习惯用法,或者unless
是defined?
unless
使用长块forms而不是单行formsdefined?
保持一致。
为了占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"