Каков наиболее эффективный способ инициализации класса в Ruby с другими параметрами и значениями по умолчанию? - PullRequest
27 голосов
/ 29 декабря 2010

Я хотел бы иметь класс и некоторые атрибуты, которые вы можете установить во время инициализации или использовать его значение по умолчанию.

class Fruit
  attr_accessor :color, :type
  def initialize(color, type)
    @color=color ||= 'green'
    @type=type ||='pear'
  end
end

apple=Fruit.new(red, apple)

Ответы [ 7 ]

57 голосов
/ 29 декабря 2010

Типичным способом решения этой проблемы является использование хеша со значением по умолчанию.Ruby имеет приятный синтаксис для передачи хеш-значений, если хеш является последним параметром метода.

class Fruit
  attr_accessor :color, :type

  def initialize(params = {})
    @color = params.fetch(:color, 'green')
    @type = params.fetch(:type, 'pear')
  end

  def to_s
    "#{color} #{type}"
  end
end

puts(Fruit.new)                                    # prints: green pear
puts(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grape
puts(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate

Хороший обзор здесь: http://deepfall.blogspot.com/2008/08/named-parameters-in-ruby.html

17 голосов
/ 21 июля 2016

Начиная с Ruby 2.0, есть поддержка именованных или ключевых параметров.

Вы можете использовать:

class Fruit
  attr_reader      :color, :type

  def initialize(color: 'green', type: 'pear')
    @color = color
    @type = type
  end

  def to_s
    "#{color} #{type}"
  end
end

puts(Fruit.new)                                    # prints: green pear
puts(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grape
puts(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate

Некоторые интересные заметки на эту тему:

10 голосов
/ 29 декабря 2010

Ответ Брайана отличный, но я хотел бы предложить некоторые модификации, чтобы сделать его в основном мета:

class Fruit

  # Now this is the only thing you have to touch when adding defaults or properties
  def set_defaults
    @color ||= 'green'
    @type  ||= 'pear'
  end

  def initialize(params = {})
    params.each { |key,value| instance_variable_set("@#{key}", value) }
    set_defaults
    instance_variables.each {|var| self.class.send(:attr_accessor, var.to_s.delete('@'))}
  end

  def to_s
    instance_variables.inject("") {|vars, var| vars += "#{var}: #{instance_variable_get(var)}; "}
  end

end

puts Fruit.new
puts Fruit.new :color => 'red', :type => 'grape'  
puts Fruit.new :type => 'pomegranate'
puts Fruit.new :cost => 20.21
puts Fruit.new :foo => "bar"


f = Fruit.new :potato => "salad"
puts "f.cost.nil? #{f.cost.nil?}"

Какие выходы:

@color: green; @type: pear; 
@color: red; @type: grape; 
@color: green; @type: pomegranate; 
@color: green; @type: pear; @cost: 20.21; 
@color: green; @type: pear; @foo: bar; 
f.cost.nil? true

Конечно, это не идеальное решение для всего, но оно дает вам некоторые идеи по повышению динамичности вашего кода.

5 голосов
/ 29 декабря 2010

Я бы сделал это так:

class Fruit
  attr_accessor :color, :type

  def initialize(args={})
    options = {:color => 'green', :type => 'pear'}.merge(args)

    self.color = options[:color]
    self.type  = options[:type]
  end
end

apple = Fruit.new(:color => 'red', :type => 'apple')

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

3 голосов
/ 30 июля 2015

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

3 голосов
/ 29 декабря 2010

Более простой способ:

class Fruit
  attr_accessor :color, :type
  def initialize(color = 'green', type = 'pear')
    @color = color
    @type = type
  end
  def to_s
    "#{color} #{type}"
  end
end


puts Fruit.new # prints: green pear
puts Fruit.new('red','apple') # prints: red apple
puts Fruit.new(nil,'pomegranate') # prints: green pomegranate
1 голос
/ 08 января 2016

Еще вкуснее синтаксического сахара:

class Fruit
  attr_accessor :color, :type
  def initialize *args
    @color, @type = args 
  end
end

pear = Fruit.new 'green', :pear
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...