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

Posted

技术标签:

【中文标题】如何在 Ruby 中记忆一个可能返回 true、false 或 nil 的方法?【英文标题】:How can I memoize a method that may return true, false, or nil in Ruby? 【发布时间】:2012-06-24 21:59:25 【问题描述】:

显然||= 不起作用

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

有没有更传统或更有效的方法来做到这一点?

更新我意识到除了false之外我还想记住nil - 这一直追溯到https://rails.lighthouseapp.com/projects/8994/tickets/1830-railscachefetch-does-not-work-with-false-boolean-as-cached-value - 我向Andrew Marshall道歉正确答案。

【问题讨论】:

这就是nilnull 的整个概念的用途。 我编辑了我的问题,因为我第一次没有做对 - 我也想记住 nil。 【参考方案1】:

明确检查@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 就被定义到达条件之前。但是,实例变量并非如此,因为它们默认为nil,解析器在遇到= 时不会定义它们。无论如何,我认为使用orunless 的长块形式而不是单行unlessdefined? 保持一致是一个很好的习惯用法。

【讨论】:

我要对此表示赞同,因为它是我问题第一个版本的答案,但请看看我的编辑——再次道歉。 @SeamusAbshere 我已经更新了我的答案以反映您的更新:) a = 42 unless defined?(a) 使a 为零,但@a = 42 unless defined?(@a) 使@a 为42,因此在此示例中并非绝对需要or 语法。 @AndrewGrimm 嗯,我想我验证了它与实例变量的行为相同,但看来你是正确的。我认为这是因为 @a 已经有一个值,即使它没有被定义。 @SeamusAbshere 我已经更新了我的答案,以反映实例变量影响最后一位的方式。【参考方案2】:

要说明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"

【讨论】:

以上是关于如何在 Ruby 中记忆一个可能返回 true、false 或 nil 的方法?的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 中,是不是有类似于 `any?` 的方法返回匹配项(而不是 `true`)

Ruby:为什么`puts true和false`返回true? [重复]

获取 ruby​​ 函数对象本身

js基础知识记忆部分(巩固基础专用)

如何使用 Ruby 将任何模式与任何字符串匹配?

如何使用 Python 的 ast 创建类型化的返回? - `def f() -> bool: return True`