歌の歌詞について考えてみよう(本当の歌詞を出すと著作権の侵害となりJASRACに怒られるので架空の歌詞とする)。多くの歌ではサビの部分は共通している。このため歌詞カードを見ると、2回目や3回目に登場するときは「*繰り返し」とだけ書かれていることが多い。
1.うんたらかんたら うんたらかんたら たりらり〜〜〜 *ららららら〜 れれれれれ〜 2.なんたらかんたら なんたらかんたら てれてれ〜〜〜 *繰り返し
もちろん、サビの部分で同じことを繰り返し書いても構わない。しかし、「*繰り返し」の方が効率的であるし、行数も短くて済む。プログラムにおいても効率化を考えて、同じことを繰り返し書くかわりに以下のような構造をとることがある。あらかじめ冒頭に繰り返し部を記載しておき、プログラムの本文中で、必要に応じて呼び出すというものである。
これにより、同じことを何度も書く必要がなくなる。冒頭で呼び出されるプログラムを記載しておき、必要に応じて呼び出すために用いるのがdef-endである。def-endを用いる場面として以下をあげることができる。
def-endの基本構造は以下の通りとなる。
def メソッド名(引数リスト) 定義本体 end
簡単な例をみてみよう。
#!/usr/koeki/bin/ruby def plus(x) return x + 10 end printf ("10に10を足すと%dになります\n", plus(10)) printf ("20に10を足すと%dになります\n", plus(20))
def-endで定義されたplusをメソッドと呼ぶ。このプログラムでは冒頭でplusメソッドを定義し、その下で実際にplusメソッドを呼び出して活用している。
def plus(x)とあるが、このうち(x)は引数リストと呼ぶ。これはplusメソッドを実行するためには引数が1つ必要であるということを意味する。メソッドと引数の関係をまとめると以下のようになる。
引数として指定する変数名はxでもyでもaでもbでも何でも構わない。
このプログラムで使われているplusメソッドに話を戻そう。def-end内を見ると、次のように書かれている。
def plus(x) return x + 10 end
このメソッドは引数を1つ必要とし、具体的には2行目にあるreturn x + 10を実行する。returnは呼び出されたところに返すという意味なので、呼び出されたときに与えられた引数xに10を足した値を返すということになる。
今度は、このプログラムの下部を見てみよう。
printf ("10に10を足すと%dになります\n", plus(10)) printf ("20に10を足すと%dになります\n", plus(20))
printfを用い、%dに表示する変数として、plus(10)およびplus(20)と書いている。ここでplusメソッドを呼び出している。plusメソッドは引数を1つ必要とするメソッドであるため、引数として10を与えている。
plusメソッドが呼び出されるとdef-endの部分に移動する。引数として10を与えた場合はxに10が代入されplusメソッドが実行される。つまり10+10が行われ、その結果の20が呼び出した場所に返される。
続けて幾つかの例を見ていきながらdef-endの用法について確認してみよう。
#!/usr/koeki/bin/ruby def shohizei(a) a * 1.05 end print "金額を入力してください" item = gets.chomp!.to_i printf ("税込み金額は%d円です\n", shohizei(item))
shohizeiメソッドは引数を1つ必要とするメソッドであり、1.05倍した値を返す。ここではa * 1.05となっており、returnがついていない。returnはつけてもつけなくても構わない。
shohizeiメソッドを呼び出しているのは最後のprintfの行であり、printf ("税込み金額は%d円です\n", shohizei(item))という形で呼び出している。itemはユーザが入力した金額が代入されており、これを引数として指定することで、shohizeiメソッドは1.05倍した結果を返してくれる。このようにメソッドを呼び出す際の引数として変数を指定することもできる。
shohizeiメソッドが呼び出されると、aにitemが代入され1.05倍される。その結果がprintfの行に返される。
#!/usr/koeki/bin/ruby def tax(x) price = x * 1.05 printf ("税込み価格は%d円です\n",price) end STDERR.print "金額を入力してください" item = gets.chomp!.to_i tax(item)
これも消費税を求めるメソッドを作成した例である。ただしtaxメソッドはshohizeiメソッドと比較して、def-end内の行数が1行増えている。shohizeiメソッドは単に与えられた引数を1.05倍して返すだけであったが、taxメソッドは与えられた引数を1.05倍し、printfで結果を表示してくれる。この場合、呼び出した場所へ返されるのは最終行のprintfの行となる。
さらに、taxメソッドを呼び出す際の方法も異なっている。上記のプログラムでは、単にtax(item)とだけ記している。shohizeiメソッドは計算をした結果の数字を返してくれるだけであるため、その数字を表示できるような形で(すなわちprintfを使って)呼び出す必要がある。一方、taxメソッドではメソッドの働き自体にprintfによる表示が含まれるため、単にtax(item)で呼び出せば、計算をして結果も表示してくれることとなる。
次のプログラムをdef-endを使って書き換えてみよう。平均点を算出するメソッドの名前はaveとすること。
#!/usr/koeki/bin/ruby print "前期の試験の得点を入力してください:" first = gets.chomp!.to_f print "後期の試験の得点を入力してください:" second = gets.chomp!.to_f average = (first + second) / 2 printf ("平均点は%5.2f点です。\n", average)
制限時間は10分。出席点は2点。提出要領は下記の通り。
Tips:emacsでの日本語入力のオンオフはCtrl-oです
Tips:Mewによるメールの送り方はMewコマンドを参照
ここでは、def-endを利用する上での注意点をまとめる。一部はこれまでの説明で出てきたものであり、新たに登場するものもある。後者についてはこの後で説明するが、注意点については複数の場所に記載されるとわかりづらくなるため、ここで一括して示す。
#!/usr/koeki/bin/ruby
def hello()
print "こんにちは!\n"
end
hello
引数が不要な場合は、引数リストのカッコ内は空にする。helloメソッドはprint文でメッセージを表示するので、呼び出す際も単にhelloをすれば結果が表示される。
#!/usr/koeki/bin/ruby
def triangle(x,y)
menseki = x * y / 2
printf ("面積は%4.2f平方センチメートルです\n",menseki)
end
STDERR.print "底辺をcm単位で入力してください"
teihen = gets.chomp!.to_f
STDERR.print "高さをcm単位で入力してください"
takasa = gets.chomp!.to_f
triangle(teihen, takasa)
triangleメソッドは2つの値を引数として与えると、計算をするだけではなくprintfで結果を表示する。このため呼び出す際も単にtriangle(teihen, takasa)とすればよい。
#!/usr/koeki/bin/ruby
def sankaku(x,y)
x * y / 2
end
STDERR.print "底辺をcm単位で入力してください"
teihen = gets.chomp!.to_f
STDERR.print "高さをcm単位で入力してください"
takasa = gets.chomp!.to_f
printf ("面積は%4.2f平方センチメートルです\n",sankaku(teihen, takasa))
sankakuメソッドも2つの値を引数として受け取り面積を求めるものである。ただし返り値は計算をした結果の数字であるため、呼び出し方もtriangleメソッドとは異なっている。printfで結果を表示する行の中でメソッドを呼び出し、その返り値を%fに入れ込んで表示するというような方法がとられている。
#!/usr/koeki/bin/ruby
def min(x,y)
if x < y
(return) x #returnは省略可能
else
(return) y #returnは省略可能
end
end
print "好きな数字を入力してください"
no1 = gets.chomp!.to_i
print "もう1つ好きな数字を入力してください"
no2 = gets.chomp!.to_i
printf ("%dの方が小さいです\n", min(no1,no2))
minメソッドは2つの値を引数として受け取り、小さい方の値を返す。if文を用い、条件に応じた処理が行われるが、この場合は最終行が返り値とならない。最終行が返り値にならない場合でもreturnは省略することができる。
#!/usr/koeki/bin/ruby def total(yen) #yenは数値の入っている配列 sum = 0 x = 0 while x < yen.length-1 #.lengthで配列の中のデータの個数を調べる sum += yen[x] x += 1 end sum #最終行が返り値となるので単にsumと書いている end bokin = [] i = 0 while true STDERR.print "募金お願いします(0で終了)" bokin[i] = gets.chomp!.to_i if bokin[i] == 0 then break end i += 1 end printf ("募金の合計は%d円でした\n",total(bokin))
プログラム下部ではbokinを配列として定義し、while-endの繰り返しを行う中で次々にbokinに値を代入している。最後にtotal(bokin)で配列のbokinを引数としてtotalメソッドに引き渡している。defの横はtotal(yen)と書いており、yenはdef-end内では配列として扱われている。配列と引数とする場合でもtotal(yen)の部分に特別な書き方はない。yenを配列扱いとして以後処理すればよい。
引数が必要なメソッドにおいて、引数が省略された場合に適用される値(デフォルト値)を指定しておくことができる。
#!/usr/koeki/bin/ruby
def sankaku(x,y=10)
x * y / 2
end
printf ("面積は%4.2f平方センチメートルです\n", sankaku(5))
printf ("面積は%4.2f平方センチメートルです\n", sankaku(5,8))
sankakuメソッドは2つの引数を受け取り、面積を計算してその値を返すメソッドである。本来2つの引数が必要であり、sankaku(5,8)のように2つの引数を与えるのが通常の呼び出し方である。しかし、このプログラムではsankaku(5)で呼び出している。
一方、def-endではsankaku(x,y=10)としてyに最初から10というデフォルト値を与えている。このため、sankaku(5)で呼び出した場合にはxに5が代入され、yは10が使用される。sankaku(5,8)で呼び出すとxには5、yには8が代入される。
メソッドを呼び出す際に与える引数は、先頭から順番に与えられる。上記の例でsankaku(5)とすると、5は必ずxに代入される。このため2つの引数を用いるメソッドを定義する際に、先頭の引数にデフォルト値を与え、2つ目の引数にデフォルト値を与えない場合、sankaku(5)で呼び出すとxに5が代入され、yには値がないことになる。この場合は実行するとエラーとなる。引数が2つの場合デフォルト値の与え方は以下の3種類があるが、×の場合はうまく動かないことがある。
○ def sankaku(x=10, y=8) ○ def sankaku(x, y=8) × def sankaku(x=10, y)
プログラムを楽しくするために様々なテクニックがある。いくつか例をあげてみよう。
#!/usr/koeki/bin/ruby janken = ["グー","チョキ","パー"] srand comp=rand(3) STDERR.print "じゃんけんぽん!(0: ぐー,1: ちょき,2: ぱー) :" user = gets.chomp!.to_i printf "あなたは %s でした \n", janken[comp] printf "わたしは %s でした。\n", janken[user]
#!/usr/koeki/bin/ruby srand rocket = rand(2) print "打ち上げ10秒前\n" sleep(1) 9.downto(1) do |i| printf ("%s秒前\n",i) sleep(1) end if rocket == 1 print "打ち上げ成功!!\n" else print "ドカーン!!\n" end
#! /usr/koeki/bin/ruby list = ["赤","黄","青"] print "あなたの反応時間を計測します。準備は良いですか(y or n)" junbi = gets.chomp! if junbi == "y" sleep(1) print "赤と表示されたら1、黄なら2、青なら3を押してください。\n" else print "そうですかさようなら\n" exit(1) end sleep(1) srand color = rand(3) print "\n" printf ("%s\n",list[color]) start = Time.now choice = gets.chomp.to_i reaction_time = Time.now - start printf ("表示されたのは%s、あなたの回答は%s\n",list[color],list[choice-1]) if color == choice-1 print "正解です\n" else print "はずれです\n" end printf ("反応時間は%s秒でした\n",reaction_time)
問題(8点満点):def-endを用いて面白いプログラムを作ってみよう。randやsleep、Time.nowなどを使ってみても良い。
Tips:emacsでの日本語入力のオンオフはCtrl-oです
Tips:ktermでのプログラムの実行結果をメールに貼り付けるには、コピーしたい箇所をマウスで選択し、emacs(Mew)上でマウスの真ん中ボタンをクリックする
Tips:Mewによるメールの送り方はMewコマンドを参照