使用不同的参数和默认值在Ruby中初始化类的最有效方法是什么?

Ist*_*van 29 ruby oop class

我希望有一个类和一些属性,您可以在初始化期间设置或使用其默认值.

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

apple=Fruit.new(red, apple)
Run Code Online (Sandbox Code Playgroud)

Bri*_*per 60

解决此问题的典型方法是使用具有默认值的哈希.如果哈希是方法的最后一个参数,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
Run Code Online (Sandbox Code Playgroud)

这里有一个很好的概述:http://deepfall.blogspot.com/2008/08/named-parameters-in-ruby.html


knu*_*nut 19

从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
Run Code Online (Sandbox Code Playgroud)

关于这个主题的一些有趣的注释


小智 10

Brian的答案非常好,但我想建议一些修改,使其主要是meta:

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?}"
Run Code Online (Sandbox Code Playgroud)

哪个输出:

@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
Run Code Online (Sandbox Code Playgroud)

当然,这对于一切都不是一个完美的解决方案,但它会为您提供一些使您的代码更具动态性的想法.


von*_*rad 5

我这样做:

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')
Run Code Online (Sandbox Code Playgroud)

这样,您就不必担心缺少参数 - 或者他们的订单 - 并且您将始终拥有默认值..merge如果它们存在,它们当然会覆盖默认值.


ace*_*reg 5

我喜欢冯康拉德的回答,但会有一个单独的defaults方法。也许它在代码行方面效率不高,但它更能揭示意图并且涉及更少的认知开销,而更少的认知开销意味着更有效的开发入门。

class Fruit
  attr_accessor :color, :type

  def initialize(args={})
    options = defaults.merge(args)

    @color = options.fetch(:color)
    @type  = options.fetch(:type)
  end

  def defaults
    {
      color: 'green',
      type:  'pear'
    }
  end
end

apple = Fruit.new(:color => 'red', :type => 'apple')
Run Code Online (Sandbox Code Playgroud)