使用默认命名参数将`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