使用默认命名参数将`nil`传递给方法
在Rails项目中,我收集了一个包含10-15个键值对的哈希,并将其传递给一个类(服务对象)进行实例化。 应该从散列中的值设置对象属性,除非没有值(或nil
)。 在这种情况下,期望将属性设置为默认值。
在创建对象之前,我没有检查散列中的每个值是否都是nil
,而是希望找到一种更有效的方法。
我正在尝试使用默认值的命名参数。 我不知道这是否有意义,但我想在使用nil
调用参数时使用默认值。 我为此function创建了一个测试:
class Taco def initialize(meat: "steak", cheese: true, salsa: "spicy") @meat = meat @cheese = cheese @salsa = salsa end def assemble "taco with: #@meat + #@cheese + #@salsa" end end options1 = {:meat => "chicken", :cheese => false, :salsa => "mild"} chickenTaco = Taco.new(options1) puts chickenTaco.assemble # => taco with: chicken + false + mild options2 = {} defaultTaco = Taco.new(options2) puts defaultTaco.assemble # => taco with: steak + true + spicy options3 = {:meat => "pork", :cheese => nil, :salsa => nil} invalidTaco = Taco.new(options3) puts invalidTaco.assemble # expected => taco with: pork + true + spicy # actual => taco with: pork + +
如果要遵循面向对象的方法,可以在单独的方法中隔离默认值,然后使用Hash#merge
:
class Taco def initialize (args) args = defaults.merge(args) @meat = args[:meat] @cheese = args[:cheese] @salsa = args[:salsa] end def assemble "taco with: #{@meat} + #{@cheese} + #{@salsa}" end def defaults {meat: 'steak', cheese: true, salsa: 'spicy'} end end
然后按照@sawa的建议(谢谢),使用Rails的Hash#compact
作为已明确定义nil
值的输入哈希值,您将得到以下输出:
taco with: chicken + false + mild taco with: steak + true + spicy taco with: pork + true + spicy
编辑:
如果你不想使用Rails的精彩Hash#compact
方法,你可以使用Ruby的Array#compact
方法。 将initialize
方法中的第一行替换为:
args = defaults.merge(args.map{|k, v| [k,v] if v != nil }.compact.to_h)
使用命名参数传递值后,对该方法调用访问该参数的默认值即可。
你要么必须(i)不在方法配置文件中,而是在方法体中分配默认值,如sagarpandya82的答案,或者(ii)在使用Rails’Hash Hash#compact
将参数传递给方法之前删除nil
值:
options3 = {:meat => "pork", :cheese => nil, :salsa => nil} invalidTaco = Taco.new(options3.compact)
在您的情况下,我认为关键字参数不合适。 似乎Hash更适合。
class Taco attr_accessor :ingredients def initialize(ingredients = {}) @ingredients = ingredients end def assemble "taco with: #{ingredients[:meat]} + #{ingredients[:cheese]} + #{ingredients[:salsa]}" end end
您甚至可以缩短assemble
方法以列出所有成分
def assemble string = "taco with: " + ingredients.values.join(" + ") end
它会像你期望的那样工作
options1 = {:meat => "chicken", :cheese => false, :salsa => "mild"} chicken_taco = Taco.new(options1) puts chicken_taco.assemble() # output: taco with: chicken + false + mild
值得一提的是,Ruby喜欢chicken_tacos
不是chickenTacos
。