Ruby 使用默认命名参数将“nil”传递给方法

Ruby 使用默认命名参数将“nil”传递给方法,ruby,named-parameters,Ruby,Named Parameters,在Rails项目中,我正在收集一个包含10-15个键值对的散列,并将其传递给一个类(服务对象)进行实例化。除了没有值(或nil)外,应根据哈希中的值设置对象属性。在这种情况下,希望将属性设置为默认值 在创建对象之前,我不想检查散列中的每个值是否不是nil,而是想找到一种更有效的方法 我正在尝试使用带有默认值的命名参数。我不知道这是否有意义,但我想在使用nil调用参数时使用默认值。我为此功能创建了一个测试: class Taco def initialize(meat: "steak", ch

在Rails项目中,我正在收集一个包含10-15个键值对的散列,并将其传递给一个类(服务对象)进行实例化。除了没有值(或
nil
)外,应根据哈希中的值设置对象属性。在这种情况下,希望将属性设置为默认值

在创建对象之前,我不想检查散列中的每个值是否不是
nil
,而是想找到一种更有效的方法

我正在尝试使用带有默认值的命名参数。我不知道这是否有意义,但我想在使用
nil
调用参数时使用默认值。我为此功能创建了一个测试:

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 +  +

我认为关键字参数不适合你的情况。看起来杂烩更合适

class Taco
    attr_accessor :ingredients

    def initialize(ingredients = {})
        @ingredients = ingredients
    end

    def assemble
        "taco with: #{ingredients[:meat]} + #{ingredients[:cheese]} + #{ingredients[:salsa]}"
    end
end
您甚至可以缩短
assembly
方法来列出所有成分

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\u tacos
而不是
chickenTacos

一旦您通过一个命名参数传递了一个值,那么该方法调用就不再访问该参数的默认值

您必须(i)在sagarpandya82的答案中,不是在方法概要文件中而是在方法主体中指定默认值,或者(ii)在使用Rails的Hash#compact将参数像这样传递给方法之前,删除
nil
值:

options3 = {:meat => "pork", :cheese => nil, :salsa => nil}
invalidTaco = Taco.new(options3.compact)

如果您想采用面向对象的方法,可以在单独的方法中隔离默认值,然后使用
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
方法。将
初始化
方法中的第一行替换为:

args = defaults.merge(args.map{|k, v| [k,v] if v != nil }.compact.to_h)

谢谢你的回答!有没有办法为您在回答中提到的一些
成分
散列键提供默认值?例如,如果
没有作为配料提供,它仍然会打印
墨西哥玉米卷,并带有:{default_meat}+{other_component_a}+…
配料[:meat]| |=“default meat”
将允许您有条件地为该键指定默认值(如果未指定)。我删除了我的答案,因为我无法获得所需的输出。如果您知道如何修复,请随意将其纳入您的答案。@sagarpandya2我看不出您的答案有任何错误。至少,它比公认的答案要好得多,后者甚至不考虑默认值(除了在事后对OP的评论做出的回应)。OP想要
taco,第一个字符串为:chicken+false+mild
。我的代码打印的墨西哥玉米卷带有:鸡肉+正品+淡味
。这是唯一的原因。你能看到修复方法吗?谢谢@sawa,但我认为在这种情况下使用
|
是有缺陷的,所以我提交了一个新的答案,其中包含了你的答案。@sawa我非常喜欢Hash#compact方法,它在这种情况下的使用。感谢您对Ruby语言进行了更多的介绍!感谢您提供的格式帮助sawaUsing
Hash#merge
以及
Hash#compact
是确保我的对象的属性获得默认值而不是
nil
值的一种很好的方法。非常感谢你!