如何在Ruby中只执行一次方法?有静态变量吗?

时间:2010-11-04 13:04:29

标签: ruby static

我编写了一个脚本,其中包含一些方法定义,没有类和一些公共代码。其中一些方法执行一些非常耗时的shell程序。但是,这些shell程序只需在第一次调用方法时执行。

现在在C中,我会在每个方法中声明一个静态变量,以确保这些程序只执行一次。我怎么能用Ruby做到这一点?

6 个答案:

答案 0 :(得分:10)

红宝石中有一个成语:x ||= y

def something
  @something ||= calculate_something
end

private

def calculate_something
  # some long process
end

但是如果你的'长时间运行的实用程序'可能返回错误值(false或nil),这个习惯用法就会出现问题,因为||=运算符仍会导致右侧被评估。 如果您期望错误的值,那么使用另一个变量,方式类似于DigitalRoss提出的方法:

def something
  return @something if @something_calculated
  @something = calculate_something
  @something_calculated = true
  return @something
end

首先设置@something_calculated变量,然后运行calculate_something,不要尝试保存一行代码。如果您的计算函数引发异常,则您的函数将始终返回nil并且永远不会再次调用计算。

更一般地说,在Ruby中使用实例变量。但请注意,它们在给定对象的所有方法中都是可见的 - 它们不是方法的本地方法。 如果需要所有实例共享的变量,请在类对象中定义方法,并在每个实例中调用self.class.something

class User
  def self.something
    @something ||= calculate_something
  end

  def self.calculate_something
    # ....
  end

  def something
    self.class.something
  end
end

答案 1 :(得分:4)

“memoize”宝石可能在这里很好。当你记住一个方法时,它只被调用一次:

require 'memoize'

include Memoize

def thing_that_should_happen_once
  puts "foo"
end
memoize :thing_that_should_happen_once

thing_that_should_happen_once    # => foo
thing_that_should_happen_once    # =>

答案 2 :(得分:1)

def f
  system "echo hello" unless @justonce
  @justonce = true
end

而且,嗯,如果你想让它在调用上运行一个shell命令,直到它成功,你可能会尝试:

def f x
  @justonce = system x unless @justonce
end

答案 3 :(得分:1)

def my_time_consuming_method
  @result ||= begin
    sleep 5
    true
  end
end

my_time_consuming_method # true after 5 secs
my_time_consuming_method # true directly

答案 4 :(得分:1)

与此线程中的其他解决方案不同,此解决方案不要求您保持任何状态:

获取调用后删除自身的方法或使用空方法覆盖自身:

def hello
  puts "hello"
  define_singleton_method(:hello) {}
end

OR:

def hello
  puts "hello"
  singleton_class.send(:undef_method, __method__)
end

答案 5 :(得分:0)

确保shell命令只运行一次是一种重复出现的模式。我编写的一个解决方案是对命令行上的输入文件进行校验和,并且只在shell命令之前没有运行时才执行它。当输入文件发生变化时,它也会再次执行。参见

https://github.com/pjotrp/once-only

只需在shell命令中加上'once-only'即可使用它。 E.g。

bowtie -t e_coli reads/e_coli_1000.fq e_coli.map

变为

once-only bowtie -t e_coli reads/e_coli_1000.fq e_coli.map

对于PBS添加--pbs开关。