2010-11-04 25 views
4

我寫了一個包含幾個方法定義,沒有類和一些公共代碼的腳本。其中一些方法執行一些非常耗時的shell程序。但是,這些shell程序只需要在第一次調用該方法時執行。如何在Ruby中只執行一次方法?有靜態變量嗎?

現在在C中,我會在每個方法中聲明一個靜態變量,以確保這些程序只執行一次。我怎麼能在Ruby中做到這一點?

回答

8

有紅寶石成語:x ||= y

def something 
    @something ||= calculate_something 
end 

private 

def calculate_something 
    # some long process 
end 

但有這個成語一個問題,如果你的「長期運行的程序」可能會返回一個假值(false或無),因爲||=運營商仍然將導致評估的右側。 如果您希望假值,則使用一個額外的變量,在類似的方式提出DigitalRoss:

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

不要試圖通過先設定@something_calculated變量,然後運行保存一行代碼calculate_something。如果您的計算函數引發異常,您的函數將始終返回零,並且不會再次調用計算。

更一般地說,在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 
+0

這對我不起作用,因爲我只定義了方法而沒有定義類。但這真的很整潔!我應該把所有東西都包裝在一個班級中,並且每天給它打電話。 – bastibe 2010-11-04 14:22:46

+0

這將爲你工作。如果你沒有定義類,那麼你正在使用某個Object。嘗試'放self.inspect;把self.class.inspect'放在你的腳本中。 – Arsen7 2010-11-04 14:25:48

+0

事實上,在Ruby中,即使您不知道它,也始終處於對象中,並且所有實例變量都在該範圍內可見。 – 2010-11-04 14:41:14

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

而且,嗯,如果你想讓它在調用運行shell命令,直到它成功,你可以嘗試:

def f x 
    @justonce = system x unless @justonce 
end 
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

的「memoize的」寶石會是個不錯這裏。當你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 # => 
1

不像在此線程的其他解決方案,該解決方案不要求你不放任何狀態:

獲取方法調用之後除去本身或本身帶有一個空方法改寫:

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

OR:

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

確保shell命令只運行一次是循環模式。我編寫的一個解決方案是在命令行上對輸入文件進行校驗和,並僅在shell命令未運行之前執行。當輸入文件改變時它也會再次執行。見

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

在前面加上「僅一次」的shell命令簡單地使用它。例如。

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開關。