如何在Ruby中记忆可能返回true,false或nil的方法?

时间:2012-06-22 15:09:30

标签: ruby null memoization

显然||=无效

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之外我还要记住false - 这一直追溯到https://rails.lighthouseapp.com/projects/8994/tickets/1830-railscachefetch-does-not-work-with-false-boolean-as-cached-value - 我向{{向{{}}道歉3}}谁给出了一个完全正确的答案。

2 个答案:

答案 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"