2009-12-29 106 views
4

是否有更簡潔和習慣的方式來編寫下面的代碼,它用於指定一個方法的可選參數(在params/options散列中)的默認值?是否有一種慣用的方式來指定Ruby中可選參數的默認值?

def initialize(params={}) 
    if params.has_key? :verbose 
    @verbose = params[:verbose] 
    else 
    @verbose = true # this is the default value 
    end 
end 

我很想把它簡化爲這樣的事情:

def initialize(params={}) 
    @verbose = params[:verbose] or true 
end 

幾乎作品,除非你真的需要使用has_key? :verbose作爲條件,而不是僅僅評估params[:verbose],在爲了覆蓋想要指定「false」值的情況(例如,如果您想在本例中將:verbose => false作爲參數)。

我意識到,在這個簡單的例子,我可以很容易做到:

def initialize(verbose=false) 
    @verbose = verbose 
end 

,但是,在我真正的代碼,我其實有一堆可選參數(除一些必需的),我會比如將可選的部分放在params散列中,這樣我就可以很容易地只指定(按名稱)少數我想要的,而不必按順序列出它們(並且可能不得不列出其中我不想要的部分) 。

+0

Perl現在擁有// =語法來解決以這種方式檢查錯誤值的問題。我知道這對此沒有幫助。這就是爲什麼它是一個評論,而不是一個答案... – mopoke 2009-12-29 00:21:05

回答

14

一個常見的模式是使用

def foo(options = {}) 
    options = { :default => :value }.merge(options) 
end 

最終你會用options是含傳入的值,從您的默認哈希任何未提供該選項的哈希值。

+0

謝謝!這工作得很好。 – Kelan 2009-12-29 01:21:27

+1

是否有理由在merge merge上使用簡單的merge? (因爲我認爲'merge!'會更快) – horseyguy 2009-12-29 06:14:54

+0

@banister:使用'options.merge!(默認值)'會在錯誤的方向上進行覆蓋。你需要使用'defaults.merge(options)'來用指定的選項覆蓋默認值。而且,由於將結果存儲在「默認值」中會很尷尬,因此您不能使用「merge!」,而必須將結果重新分配給「選項」。 我不確定'merge'和'merge!'之間是否存在巨大的速度差異。 – Kelan 2010-02-23 23:07:33

0

我認爲你正在尋找這個

params = { :verbose => true }.merge(params) 
0

另一種方式來寫這個,更簡潔,將

def foo(options = {}) 
    options.reverse_merge! value1: true, value2: 100 
end 

這組選項[:數值1]爲true(默認值)除非已在 中傳遞的選項包含鍵:value1。同爲:VALUE2

+0

要明確,'reverse_merge!()'(和'reverse_merge()')是特定於Rails(ActiveSupport),因此不是在「純」Ruby中可用。 – mwp 2015-10-27 16:27:48

2

的Ruby 2.0.0有一項新功能keywordarguments

以前,你必須寫這樣的代碼:

def foo(options = {}) 
    options = {bar: 'bar'}.merge(options) 
    puts "#{options[:bar]} #{options[:buz]}" 
end 

foo(buz: 'buz') # => 'bar buz' 

現在,這是更清潔:

def foo(bar: 'bar', **options) 
    puts "#{bar}, #{options}" 
end 

foo(buz: 'buz') # => 'bar buz' 
相關問題