2009-12-29 5 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

ответ

14

Общий шаблон является использование

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

Вы будете в конечном итоге с options быть хэш, содержащий переданному в значениях, с параметрами из ваших умолчанию хэш, как и любой, которые не были предоставлены.

+0

Спасибо! Это работает очень хорошо. – Kelan

+1

Есть ли причина использовать простой 'merge' над' merge! '? (поскольку я предполагаю, что 'merge!' будет быстрее) – horseyguy

+0

@banister: Использование 'options.merge! (по умолчанию)' будет делать переписку в неправильном направлении. Вам нужно выполнить 'defaults.merge (options)', чтобы переписать значение по умолчанию с указанными параметрами. И, поскольку было бы неудобно хранить результат в «defaults», вы не можете использовать «merge!» И вместо этого должны возвращать результат «options». Я не уверен, существует ли большая разница в скорости между 'merge' и' merge! '. – Kelan

0

Я думаю, что вы ищете для этого

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

Другой способ, чтобы написать это, более сжато, будет

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

Этот набор опций [: value1] к истинному (значение по умолчанию) если параметры, переданные уже в , содержит ключ: value1. То же самое для: значение2

+0

Чтобы быть понятным, 'reverse_merge!()' (И 'reverse_merge()') специфичны для Rails (ActiveSupport) и, следовательно, не доступный в «чистом» Ruby. – mwp

2

Руби 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' 
Смежные вопросы