Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Ruby TIPS

Ruby TIPS

メソッドのキーワード引数を利用するには?

2017年8月25日

メソッドの呼び出し時にキーワード引数を使うと、意味が分かりやすくなるだけでなく、指定順序を変えたりできる。キーワード引数の使い方について説明する。

ローグ・インターナショナル 羽山 博
  • このエントリーをはてなブックマークに追加

 Rubyのメソッドでは、基本的に、実引数は同じ位置に書かれている仮引数に渡される。しかし、キーワード引数を利用すれば、引数の意味が分かりやすくなり、実引数の指定順序も変えられる。また、デフォルトの値も指定できる。

キーワード引数を利用するには

 キーワード引数を利用すれば、引数の名前と値が指定できる。引数の意味が分かりやすくなるので、誤りを防いだり、保守の効率を上げたりするのに役立つ。まず、キーワード引数を使わない場合の問題点から見ていこう。

キーワード引数を使わない場合

 以下のプログラムには、複利計算を行うcumpiメソッドが記述されている。cumpiメソッドの引数には、金利(interest)と期間(term)、元金(principal)を指定する。例えば、年利が1%で5年満期の定期預金に10万円預金すると、5年後には元利合計がいくらになるかが求められる。一般的な定期預金では年2回利息が付くので、その場合を想定して引数を指定してみた。

sample001.rb
def cumpi(interest, term, principal)
  principal * (1+interest)**term
end

i = 0.01    # 年利1%
t = 5       # 5年満期(利息は年2回)
p = 100000  # 元金10万円
puts cumpi(i/2, t*2, p).floor  # 複利計算を行う
puts cumpi(t*2, i/2, p).floor  # わざと引数を間違える
puts cumpi(p, t*2, i/2).floor  # わざと引数を間違える
リスト1.1 複利計算を行って元利合計を求めるプログラム

cumpiメソッドに、利率、期間、元金を指定して元利合計を求める。年に2回利息が付くので、年利1%ということは、1回あたりの利率は1%÷2となる。また、期間は5年だが、利息が付く回数を指定するので、5×2回となる。わざと引数を間違って指定した例も含めてある。

 cumpiメソッドは比較的単純なので、引数の指定にそれほど悩まないかもしれないが、それでもひと目見ただけでどの引数が何を表しているかが分かりにくい。プログラムを実行してみると、引数を間違って指定した場合の問題点がよく分かる。

ターミナル
$ ruby sample001.rb 
105114
101206
500050002250059967424263869744249811715066167296
実行例1.1 複利計算の結果

最初に出力された値は正しく計算されたものだが、2行目は少し異なっている。3行目はとんでもない値が表示されている。

 3行目の結果はあまりにも莫大な値なので、明らかに何かがおかしいと分かるが、2行目の結果は正しい値とそれほど変わらないので、間違いに気づきにくい。下手をすると間違いに気付かないまま、システムが稼働してしまうこともあり得る。

キーワード引数を使う場合

 キーワード引数を指定すれば、実引数を指定するときの誤りを減らすことができる。そこで、キーワード引数を利用できるようにcumpiメソッドを書き換えてみよう。まず、メソッドの定義時に、仮引数を「キーワード:既定値」という形式で書く。ここでは、既定値を必要とする引数はないので、既定値は記述しない。一方、メソッドを呼び出すときには「キーワード:実引数」と書けばよい。

sample002.rb
def cumpi(interest:, term:, principal:)
  principal * (1+interest)**term
end

i = 0.01    # 年利1%
t = 5       # 5年満期(利息は年2回)
p = 100000  # 元金10万円
puts cumpi(interest:i/2, principal:p, term:t*2).floor  # 複利計算を行う
puts cumpi(term:t*2, interest:i/2, principal:p).floor  # 順序を変えて指定する
puts cumpi(i/2, p, t*2)    # キーワードを指定しない
リスト1.2 キーワード引数を使って元利合計を求めるプログラム

キーワードが指定されているので、引数の順序を変えても正しく値が渡せる。なお、キーワードを指定しないとエラーになることを確認するために、その例も含めておいた。

 実行例を見てみよう。当然のことながら、引数の順序を変えても正しく結果が求められる。しかし、キーワードを指定しないとエラーになることに注意が必要である。

ターミナル
$ ruby sample002.rb 
105114
105114
sample002.rb:1:in `cumpi': wrong number of arguments (3 for 0) (ArgumentError)
  from sample002.rb:10:in `<main>'
実行例1.2 キーワード引数を使って元利合計を求めるプログラム

キーワード引数を利用すれば、引数の順序が定義と異なってもいいので、誤りが防げる。ただし、キーワードが指定されていないと他の引数を指定したものと見なされることに注意。cumpiメソッドの定義には他の引数はないので、エラーとなる。

 なお、キーワードのない引数はキーワード引数よりも前に書く必要がある。混在させることはお勧めできないが、例えば、cumpiメソッドに、xというキーワードのない引数がもう一つある場合、

Ruby
def cumpi(x, interest:, term:, principal:)

と書くことはできるが、以下のように書くことはできない。

Ruby
def cumpi(interest:, term:, principal:, x)

キーワード引数に既定値を指定する

 最後に、キーワード引数に既定値を指定した例も見ておこう。以下のプログラムに含まれるnthcodeというメソッドは、文字列の何番目かの文字コード(unicode)を10進数で返すメソッドである。引数には文字列と位置を指定する。ただし、位置を省略した場合には0が指定されたものと見なすことにしよう。

sample003.rb
def nthcode(str:, pos:0)
  str[pos].ord
end

puts nthcode(str:"hello").to_s(16)
puts nthcode(str:"ruby", pos:2).to_s(16)
リスト1.3 n文字目の文字コードを求めるプログラム

nthcodeメソッドのposという引数に、既定値として0を指定する。文字コードを求めるには、Stringクラスのordメソッドを使えばよい。結果は16進数で表示したいので、to_sメソッドに16を指定して数値を16進数表記の文字列に変換する。

 Stringクラスのordメソッドは文字列の先頭の文字のコードを返す。文字列のpos番目の文字について、ordメソッドで求めた文字コードを返せばよい。nthcodeメソッドを呼び出すときに引数posを省略した場合と、指定した場合にどうなるかを確認してみる。

ターミナル
$ ruby sample003.rb 
68
62
実行例1.3 n文字目の文字コードを表示する

最初のputsメソッドで出力された結果は、引数posを省略してnthcodeメソッドを呼び出した場合の結果である。従って、引数posに既定値の0が指定されたものとみなされ、"hello"という文字列の0文字目、つまり"h"の文字コードが表示される。次のputsメソッドで出力された結果は、引数pos2を指定してnthcodeメソッドを呼び出したものなので、"ruby"2文字目、つまり"b"の文字コードが表示される。

まとめ

 キーワード引数を利用すれば、引数の意味が分かりやすくなり、また、定義された順序と異なる順序で実引数を指定できる。ただし、キーワード引数として定義されている引数には、キーワードを指定して実引数を指定する必要がある。

処理対象:キーワード引数 カテゴリ:文法 > クラス > クラス/メソッドの定義 > メソッド定義

※以下では、本稿の前後を合わせて5回分(第21回~第25回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

Ruby TIPS
21. ファイルから1行/段落ごと読み込む(入力する)には?

Rubyでテキストファイルから文字列を読み込むための方法として、ファイル内の全テキスト内容を先頭から1行単位ずつもしくは1段落ずつループ処理する方法と、ファイルから読み込んだ全ての行を配列として返す方法を説明する。

Ruby TIPS
22. ファイルに文字列を書き込む(出力する)には?

テキストファイルに文字列を書き込むための基本を解説。新規書き込みと追加の方法を確認した後、任意の位置から書き込む方法や読み書き両用モードでファイルを利用する方法を説明する。

Ruby TIPS
23. ファイルの排他制御を行うには? その際のデッドロック問題とは?

1つのファイルに複数のプログラムから同時アクセスすると、上書きによりデータが消失する可能性がある。これを回避するために排他制御を行う方法と、その際に問題となるデッドロックを回避する方法について説明する。

Ruby TIPS
24. 【現在、表示中】≫ メソッドのキーワード引数を利用するには?

メソッドの呼び出し時にキーワード引数を使うと、意味が分かりやすくなるだけでなく、指定順序を変えたりできる。キーワード引数の使い方について説明する。

Ruby TIPS
25. 集合演算を行うには?

Rubyで配列を使って集合演算を行う方法として、「&」演算子による積集合/「|」演算子による和集合/「-」演算子による差集合を説明する。

サイトからのお知らせ

Twitterでつぶやこう!