何时使用关键字参数也称为Ruby中的命名参数

Ruby 2.0.0支持关键字参数(KA),我想知道在纯Ruby的上下文中这个特性的好处/用例是什么,特别是考虑到由于需要每个关键字匹配而导致的性能损失。时间调用带有关键字参数的方法。

require 'benchmark' def foo(a:1,b:2,c:3) [a,b,c] end def bar(a,b,c) [a,b,c] end number = 1000000 Benchmark.bm(4) do |bm| bm.report("foo") { number.times { foo(a:7,b:8,c:9) } } bm.report("bar") { number.times { bar(7,8,9) } } end # user system total real # foo 2.797000 0.032000 2.829000 ( 2.906362) # bar 0.234000 0.000000 0.234000 ( 0.250010) 

关键字参数有一些明显的优势,没有人接触过。

首先,你没有加入参数的顺序。 因此,如果您偶尔会有一个nil参数,它看起来会更清晰:

 def yo(sup, whats="good", dude="!") # do your thing end yo("hey", nil, "?") 

如果您使用关键字参数:

 def yo(sup:, whats:"good", dude:"!") # do your thing end yo(sup: "hey", dude: "?") 

甚至

 yo(dude: "?", sup: "hey") 

它消除了必须记住参数顺序的需要。 但是,缺点是您必须记住参数的名称,但这应该或多或少直观。

此外,当你有一个方法可能需要在将来采取更多的参数。

 def create_person(name:, age:, height:) # make yourself some friends end 

如果您的系统突然想知道一个人最喜欢的糖果棒,或者如果他们超重(因为消耗了太多他们喜欢的糖果棒)怎么办?你会怎么做? 简单:

 def create_person(name:, age:, height:, favorite_candy:, overweight: true) # make yourself some fat friends end 

在关键字参数之前总是存在哈希值,但这导致了更多的样板代码来提取和赋值变量。 Boilerplate代码==更多输入==更多潜在的错别字==少写一些令人敬畏的ruby代码。

 def old_way(name, opts={}) age = opts[:age] height = opts[:height] # all the benefits as before, more arthritis and headaches end 

如果您只是设置一个接受一个参数的方法,并且很可能永远不需要更改:

 def say_full_name(first_name, last_name) puts "#{first_name} #{last_name}" end 

然后应避免使用关键字参数,因为性能影响很小。

由于KA是ruby般的创新,我认为有两个主要优点:

  • 将允许的参数限制为预定义的集合,如Rails与assert_valid_keys一样 ;
  • 使用代码块中的function。

总结:

 a = lambda { |name: "Leonardo", age: 67| [name, age] } a.call # ⇒ ["Leonardo", 67] a.call name: "Michelangelo", age: 88 # ⇒ ["Michelangelo", 88] a.call name: "Schwarzenegger", alive: true # ⇒ ArgumentError: unknown keyword: alive 

从ruby-2.2.0开始,使用关键字参数的低效率问题似乎不再是问题。

function#10440修复了速度问题,并在ruby-2.2.0中发布:

Mon Nov 03 03:02:38 2014 Koichi Sasada

  • 重写方法/块参数拟合逻辑,以优化关键字参数/参数和splat参数。 function#10440 (此票据中描述了详细信息)

你可以自己看到这个(使用原始问题中给出的相同代码):

 (08:04:%) rvm use ruby-2.0.0-p247 Using /Users/adam/.rvm/gems/ruby-2.0.0-p247 (08:04:%) ruby keyword_benchmarks.rb user system total real foo 1.390000 0.060000 1.450000 ( 1.451284) bar 0.130000 0.000000 0.130000 ( 0.122344) (08:04:%) rvm use ruby-2.2.0 Using /Users/adam/.rvm/gems/ruby-2.2.0 (08:04:%) ruby keyword_benchmarks.rb user system total real foo 0.140000 0.000000 0.140000 ( 0.136194) bar 0.110000 0.000000 0.110000 ( 0.116246) 

使用关键字args仍然存在极其微不足道的性能损失,但我认为这是一种可接受的权衡,以换取增加可读性和位置灵活性的好处。

例如

一个function

 def welcome_message(message, options={}) default_options = {name: 'hoge'} options = default_options.merge(options) "#{message}、#{options[:name]}" end 

可以写

 def welcome_message(message, name: 'hoge') "#{message}、#{name}" end