Ruby 2.0.0 supports keyword arguments (KA) and I wonder what the benefits/use-cases are of this feature in context of pure Ruby, especially when seen in light of the performance penalty due to the keyword matching that needs to be done every time a method with keyword arguments is called.
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)
4 个解决方案
#1
11
Keyword arguments have a few distinct advantages no one has touched on.
关键字参数有一些明显的优势,没有人接触过。
First off you are not coupled to the order of the arguments. So in a case where you might have a nil argument occasionally it looks a lot cleaner:
首先,你没有加入参数的顺序。因此,如果您偶尔会有一个nil参数,它看起来会更清晰:
def yo(sup, whats="good", dude="!")
# do your thing
end
yo("hey", nil, "?")
if you use keyword arguments:
如果您使用关键字参数:
def yo(sup:, whats:"good", dude:"!")
# do your thing
end
yo(sup: "hey", dude: "?")
or even
甚至
yo(dude: "?", sup: "hey")
It removes the need to have to remember the order of the arguments. However, the disadvantage is you have to remember the argument's name, but that should be more or less intuitive.
它消除了必须记住参数顺序的需要。但是,缺点是您必须记住参数的名称,但这应该或多或少直观。
Also, when you have a method that could possibly have a need to take more arguments in the future.
此外,当你有一个方法可能需要在将来采取更多的参数。
def create_person(name:, age:, height:)
# make yourself some friends
end
what if your system all of the sudden wants to know about a person's favorite candy bar, or if they are overweight (from consuming too many of their favorite candy bar), how would you do that? Simple:
如果您的系统突然想知道一个人最喜欢的糖果棒,或者如果他们超重(因为消耗了太多他们喜欢的糖果棒)怎么办?你会怎么做?简单:
def create_person(name:, age:, height:, favorite_candy:, overweight: true)
# make yourself some fat friends
end
Before keyword arguments there was always the hash, but that led to a lot more boilerplate code to extract and assign variable. Boilerplate code == more typing == more potential typos == less times writing awesome ruby code.
在关键字参数之前总是存在哈希值,但这导致了更多的样板代码来提取和赋值变量。 Boilerplate代码==更多输入==更多潜在的错别字==少写一些令人敬畏的红宝石代码。
def old_way(name, opts={})
age = opts[:age]
height = opts[:height]
# all the benefits as before, more arthritis and headaches
end
If you are just setting up a method that takes one argument and will most likely never have a need to change:
如果您只是设置一个接受一个参数的方法,并且很可能永远不需要更改:
def say_full_name(first_name, last_name)
puts "#{first_name} #{last_name}"
end
Then keyword arguments should be avoided, since there is a small performance hit.
然后应避免使用关键字参数,因为性能影响很小。
#2
4
Since KA are ruby-wide innovation, I see two main advantages:
由于KA是红宝石般的创新,我认为有两个主要优点:
- limit permitted arguments to a predefined set, as Rails does with assert_valid_keys;
- 将允许的参数限制为预定义的集合,如Rails与assert_valid_keys一样;
- use the feature within code blocks.
- 使用代码块中的功能。
The summing up:
总结:
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
#3
3
The inefficiency issue of using keyword arguments no longer seems to be a problem as of ruby-2.2.0.
从ruby-2.2.0开始,使用关键字参数的低效率问题似乎不再是问题。
Feature #10440 fixed the speed issue and was released in ruby-2.2.0:
功能#10440修复了速度问题,并在ruby-2.2.0中发布:
Mon Nov 03 03:02:38 2014 Koichi Sasada
Mon Nov 03 03:02:38 2014 Koichi Sasada
- rewrite method/block parameter fitting logic to optimize keyword arguments/parameters and a splat argument. Feature #10440 (Details are described in this ticket)
- 重写方法/块参数拟合逻辑,以优化关键字参数/参数和splat参数。功能#10440(此票据中描述了详细信息)
You can see this for yourself (using the same code as given in the original question):
你可以自己看到这个(使用原始问题中给出的相同代码):
(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)
There's still an extremely negligible performance penalty for using keyword args, but I think it's an acceptable tradeoff in exchange for the benefit of increased readability and positional flexibility.
使用关键字args仍然存在极其微不足道的性能损失,但我认为这是一种可接受的权衡,以换取增加可读性和位置灵活性的好处。
#4
1
For example
例如
A function
一个功能
def welcome_message(message, options={})
default_options = {name: 'hoge'}
options = default_options.merge(options)
"#{message}、#{options[:name]}"
end
could be written
可以写
def welcome_message(message, name: 'hoge')
"#{message}、#{name}"
end
#1
11
Keyword arguments have a few distinct advantages no one has touched on.
关键字参数有一些明显的优势,没有人接触过。
First off you are not coupled to the order of the arguments. So in a case where you might have a nil argument occasionally it looks a lot cleaner:
首先,你没有加入参数的顺序。因此,如果您偶尔会有一个nil参数,它看起来会更清晰:
def yo(sup, whats="good", dude="!")
# do your thing
end
yo("hey", nil, "?")
if you use keyword arguments:
如果您使用关键字参数:
def yo(sup:, whats:"good", dude:"!")
# do your thing
end
yo(sup: "hey", dude: "?")
or even
甚至
yo(dude: "?", sup: "hey")
It removes the need to have to remember the order of the arguments. However, the disadvantage is you have to remember the argument's name, but that should be more or less intuitive.
它消除了必须记住参数顺序的需要。但是,缺点是您必须记住参数的名称,但这应该或多或少直观。
Also, when you have a method that could possibly have a need to take more arguments in the future.
此外,当你有一个方法可能需要在将来采取更多的参数。
def create_person(name:, age:, height:)
# make yourself some friends
end
what if your system all of the sudden wants to know about a person's favorite candy bar, or if they are overweight (from consuming too many of their favorite candy bar), how would you do that? Simple:
如果您的系统突然想知道一个人最喜欢的糖果棒,或者如果他们超重(因为消耗了太多他们喜欢的糖果棒)怎么办?你会怎么做?简单:
def create_person(name:, age:, height:, favorite_candy:, overweight: true)
# make yourself some fat friends
end
Before keyword arguments there was always the hash, but that led to a lot more boilerplate code to extract and assign variable. Boilerplate code == more typing == more potential typos == less times writing awesome ruby code.
在关键字参数之前总是存在哈希值,但这导致了更多的样板代码来提取和赋值变量。 Boilerplate代码==更多输入==更多潜在的错别字==少写一些令人敬畏的红宝石代码。
def old_way(name, opts={})
age = opts[:age]
height = opts[:height]
# all the benefits as before, more arthritis and headaches
end
If you are just setting up a method that takes one argument and will most likely never have a need to change:
如果您只是设置一个接受一个参数的方法,并且很可能永远不需要更改:
def say_full_name(first_name, last_name)
puts "#{first_name} #{last_name}"
end
Then keyword arguments should be avoided, since there is a small performance hit.
然后应避免使用关键字参数,因为性能影响很小。
#2
4
Since KA are ruby-wide innovation, I see two main advantages:
由于KA是红宝石般的创新,我认为有两个主要优点:
- limit permitted arguments to a predefined set, as Rails does with assert_valid_keys;
- 将允许的参数限制为预定义的集合,如Rails与assert_valid_keys一样;
- use the feature within code blocks.
- 使用代码块中的功能。
The summing up:
总结:
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
#3
3
The inefficiency issue of using keyword arguments no longer seems to be a problem as of ruby-2.2.0.
从ruby-2.2.0开始,使用关键字参数的低效率问题似乎不再是问题。
Feature #10440 fixed the speed issue and was released in ruby-2.2.0:
功能#10440修复了速度问题,并在ruby-2.2.0中发布:
Mon Nov 03 03:02:38 2014 Koichi Sasada
Mon Nov 03 03:02:38 2014 Koichi Sasada
- rewrite method/block parameter fitting logic to optimize keyword arguments/parameters and a splat argument. Feature #10440 (Details are described in this ticket)
- 重写方法/块参数拟合逻辑,以优化关键字参数/参数和splat参数。功能#10440(此票据中描述了详细信息)
You can see this for yourself (using the same code as given in the original question):
你可以自己看到这个(使用原始问题中给出的相同代码):
(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)
There's still an extremely negligible performance penalty for using keyword args, but I think it's an acceptable tradeoff in exchange for the benefit of increased readability and positional flexibility.
使用关键字args仍然存在极其微不足道的性能损失,但我认为这是一种可接受的权衡,以换取增加可读性和位置灵活性的好处。
#4
1
For example
例如
A function
一个功能
def welcome_message(message, options={})
default_options = {name: 'hoge'}
options = default_options.merge(options)
"#{message}、#{options[:name]}"
end
could be written
可以写
def welcome_message(message, name: 'hoge')
"#{message}、#{name}"
end