Какой хороший чистый способ использовать хэш параметров со значениями по умолчанию в качестве параметра в ruby

предположим, мне нужен метод, который будет называться так:

 tiger = create_tiger( :num_stripes => 12, :max_speed => 43.2 )
 tiger.num_stripes # will be 12

где некоторые параметры имеют значения по умолчанию:

 tiger = create_tiger( :max_speed => 43.2 )
 tiger.num_stripes # will have some default value

каков хороший идиоматический ruby-способ реализации этого поведения по умолчанию в реализации метода?

4 ответов


Если вы используете Rails (а не просто Ruby), немного более короткий метод -

def foo(options = {})
  options.reverse_merge! { ... defaults ... }
end

это имеет дополнительное преимущество, позволяя вам делать несколько линий, немного более чистоплотными:

def foo(options = {})
  options.reverse_merge!(
    :some_default => true,
    :other_default => 5
  )
end

def foo(options = {})
  options = { ... defaults ... }.merge(options)
end

обычно лучше инкапсулировать безопасные значения по умолчанию в хэш, объявленный как константа. Например:

требуется 'ostruct'

require 'ostruct'

class Tiger < OpenStruct
  DEFAULTS = {
    :num_stripes => 12,
    :max_speed => 43.2
  }.freeze

  def initialize(options = { })
    super(DEFAULTS.merge(options))
  end
end

tiger = Tiger.new(:max_speed => 19.95)

puts tiger.max_speed
puts tiger.num_stripes

при слиянии хэш-объектов важно отметить, что ключи String и Symbol различны и не будут объединены, как можно было бы ожидать. В среде Rails вы всегда можете конвертировать один в другой, используя хэш#symbolize_keys или объявив их как HashWithIndifferentAccess, который отображает разницу для вы.


в случае, если кто-то видит это из google, этот вопрос устарел и устарел. Современный и гораздо более чистый ответ (с Ruby > 2.0) - использовать аргументы ключевых слов. У них есть несколько преимуществ.

1.) вы можете потребовать имя ключа в хэше. (в ruby > 2.1)

2.) вам не нужно "распаковывать" хэш в функции. Ключи просто вручены вам как переменные. (таким образом, вам не нужно делать like speed = opts[:speed])

3.) Это чище!--3-->

def foo(num_stripes: 12, **rest)
  print num_stripes, rest
end

foo({max_speed: 42}) # would print '12, {max_speed: 42}'

см. полные документы ruby здесь: http://www.ruby-doc.org/core-2.1.0/doc/syntax/methods_rdoc.html#label-Array%2FHash+Argument

и хороший маленький пост в блоге здесь:http://robots.thoughtbot.com/ruby-2-keyword-arguments