web-dev-qa-db-ja.com

いつキーワード引数を使用するか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)
17
saihgala

キーワード引数には、誰も触れていないいくつかの明確な利点があります。

まず第一に、あなたは議論の順序に縛られていません。したがって、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

キーワード引数の前には常にハッシュがありましたが、それは変数を抽出して割り当てるためのより多くの定型コードにつながりました。ボイラープレートコード==より多くのタイピング==より多くの潜在的なタイプミス==より少ない回数の素晴らしいRubyコード。

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

1つの引数を取るメソッドを設定するだけで、変更する必要がほとんどない場合:

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

次に、パフォーマンスへの影響が小さいため、キーワード引数は避ける必要があります。

17
Davey

KAはRuby全体のイノベーションであるため、2つの主な利点があります。

  • Railsは assert_valid_keys ;と同じように、許可された引数を事前定義されたセットに制限します。
  • コードブロック内でこの機能を使用します。

まとめ:

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
4

Ruby-2.2.0以降、キーワード引数を使用することによる非効率的な問題は問題ではなくなったようです。

機能#1044 速度の問題を修正し、 Ruby-2.2. でリリースされました:

月11月3日03:02:382014笹田耕一

  • メソッド/ブロックパラメータフィッティングロジックを書き直して、キーワード引数/パラメータとスプラット引数を最適化します。 機能#1044 (詳細はこのチケットに記載されています)

あなたはこれをあなた自身で見ることができます(元の質問で与えられたのと同じコードを使用して):

(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)

キーワード引数を使用した場合のパフォーマンスの低下はごくわずかですが、読みやすさと位置の柔軟性の向上と引き換えに、許容できるトレードオフだと思います。

4
adamc

例えば

機能

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
1
oldergod