用不同的参数和默认值在 Ruby 中初始化类的最有效方法是啥?
Posted
技术标签:
【中文标题】用不同的参数和默认值在 Ruby 中初始化类的最有效方法是啥?【英文标题】:What is the most efficient way to initialize a Class in Ruby with different parameters and default values?用不同的参数和默认值在 Ruby 中初始化类的最有效方法是什么? 【发布时间】:2011-06-01 01:24:25 【问题描述】:我想要一个类和一些属性,您可以在初始化期间设置或使用其默认值。
class Fruit
attr_accessor :color, :type
def initialize(color, type)
@color=color ||= 'green'
@type=type ||='pear'
end
end
apple=Fruit.new(red, apple)
【问题讨论】:
【参考方案1】:解决此问题的典型方法是使用具有默认值的哈希。如果哈希是方法的最后一个参数,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
【讨论】:
我最喜欢这个解决方案。原因是我们不需要创建任何更重要的对象(例如想象一个大类实例),以防参数已经具有这些选项。但我也想使用更简洁的语法(只是我的意见):@color = params[:color] || '绿色' 我将有机会做一点 ruby/jruby! 7年后!【参考方案2】:从 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
关于这个主题的一些有趣的笔记:
Keyword arguments in Ruby 2.0 Ruby 2.0.0 by Example Named parameters in Ruby 2【讨论】:
明确地说,这是迄今为止最好的答案,尽管正如 knut 所说,kwargs 直到 Ruby 2.0 才可用。【参考方案3】:Brian 的回答非常好,但我想建议一些修改,使其主要是元:
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
当然,这并不是所有事情的完美解决方案,但它为您提供了一些关于使您的代码更加动态的想法。
【讨论】:
谢谢!我以后可能会考虑切换到这个。 @l1x 很高兴我能帮上忙。如果信息有帮助,投票会很酷。 ;)【参考方案4】:我会这样做:
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
当然会覆盖默认值(如果存在)。
【讨论】:
【参考方案5】:我喜欢 vonconrad 的回答,但会有一个单独的 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')
【讨论】:
【参考方案6】:更简单的方法:
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
【讨论】:
是的,除了这种方法要求您按顺序传递参数。使用散列方法,您必须指定参数名称(即散列键),但您可以按任意顺序传递这些键。【参考方案7】:更美味的语法糖:
class Fruit
attr_accessor :color, :type
def initialize *args
@color, @type = args
end
end
pear = Fruit.new 'green', :pear
【讨论】:
这不允许你设置默认值。以上是关于用不同的参数和默认值在 Ruby 中初始化类的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章