引数
違うスコープの変数を利用する
下記のソースコードではエラーが出る
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
def post_review
# 変数の定義
post = {}
puts "ジャンルを入力してください:"
post[:genre] = gets.chomp
puts "タイトルを入力してください:"
post[:title] = gets.chomp
puts "感想を入力してください:"
post[:review] = gets.chomp
line = "---------------------------"
# レビューの描画
puts "ジャンル : #{post[:genre]}\n#{line}"
puts "タイトル : #{post[:title]}\n#{line}"
puts "感想 :\n#{post[:review]}\n#{line}"
# 配列オブジェクトに追加
posts << post
end
## 以下省略
|
18行目の配列オブジェクトpostsは、post_reviewメソッドの外で定義した変数なのでpost_reviewメソッド内では使えない。
「メソッドの外で定義した変数」を「メソッドの中」で使えるようにするには引数を使う。
引数(ひきすう)
引数(ひきすう)はプログラムでメソッドなどに渡すことのできる値のこと。引数(ひきすう)を使うことによって、メソッドの外にある変数(スコープ外の変数)をメソッドの中で使うことができる。
引数でメソッドに変数を渡す
メソッドは「何か材料を渡したら共通の処理を施した後に何か値を返してくれるもの」と表現することができる。ジューサーはジュースを作るものだが、リンゴを材料とするとリンゴジュースが、オレンジを材料とすればオレンジジュースができる。材料とするものによって出来上がるジュース(結果)が変わる。引数は、この時のリンゴやオレンジのような材料にあたる。引数によってメソッドの実行結果は変わるということになる。
引数のポイント
引数には以下の2つのポイントがある。
- 引数は「メソッドを呼び出す部分」と「メソッドを定義している部分」両方に書く
- 「メソッドを呼び出す部分」に書く引数と「メソッドを定義している部分」に書く引数の名前は、一致している必要はない
1. 引数は、「メソッドを呼び出す部分」と「メソッドを定義している部分」両方に書く
メソッドを呼び出す際に書く引数のことを本引数と言う。メソッドの呼び出し時は、以下のように本引数を書く。
1 |
メソッド名(本引数)
|
本引数に対して、メソッドを定義している部分に書く引数のことを仮引数と言う。メソッドを定義している部分には、以下のように仮引数を書く。メソッドの処理の中では、引数として渡されたものを仮引数としてつけた名前で扱う。
1 2 3 |
def メソッド名(仮引数)
実行する処理
end
|
【例】引数を用いたメソッドの実行
1 2 3 4 5 6 7 8 |
def multi(input)
puts input * input
end
puts "何か数字を入力してください"
input = gets.to_i
multi(input)
|
メソッドmulti
は、引数として渡した数を2乗した数字を出力してくれるメソッド。
1 ~ 3行目でメソッドmultiを定義する。5行目のputsメソッドで「何か数字を入力してください」と出力されたあと、6行目でユーザーが入力した数字が変数input
に代入される。
そして、8行目でメソッドmulti
を実行している。その際、メソッドの名の後ろの()の中にinput
が書かれていることに注目する。この記述により、メソッドmulti
が実行される際にinput
を引数として利用することが出来る。
1行目、メソッドの定義側を見ると、仮引数はinput
となっている。なので、メソッドmulti
の処理中は、本引数input
をinput
という変数として利用することになる。
2. 「メソッドを呼び出す部分」に書く引数と「メソッドを定義している部分」に書く引数の名前は同じである必要はない
どのような名前の本引数が渡されても、メソッドの中では仮引数の名前で扱うため、本引数と仮引数の名前が同じである必要はない。
引数が渡されたメソッドの性質によって名前を変えた方がわかりやすい場合がある。例えば、先ほどのメソッドの仮引数を以下のようにしても問題なく動作する。
【例】仮引数の名前を変更
1 2 3 4 5 6 7 8 |
def multi(number)
puts number * number
end
puts "何か数字を入力してください"
input = gets.to_i
multi(input)
|
仮引数の変数名をnumberに変更。inputとしてメソッドmulti
に引き渡された引数の値は、メソッドmulti
の中では変数number
に代入された状態で利用される。
仮引数の名前について
仮引数の名前は何でも良いのですが、どんな人が読んでもそれが何なのかわかるものにするべき。例えば、メソッドの仮引数がa
やb
では、それが何なのかわかりづらくなる。
【例】わかりづらい仮引数
1 2 3 |
def multi(a)
puts a * a
end
|
メソッドmulti
の中で掛け合わされるのは必ず数字なので、ここはnumber
にするべき。
メソッド自体の答えを明示的に示すreturn文
現在メソッドmulti
は引数として渡された数字の2乗の結果を出力するだけ。この結果をメソッド自体の値とする場合は、以下のように3行目を追記する。
1 2 3 4 5 6 7 8 9 |
上記のようにすることで、9行目のメソッドmulti
の式の答えはnumber * numberの答えになる。
return
全てのメソッドには返り値があると、紹介した。メソッド内でreturn ◯◯
とすると、return(リターン)のあとに続けた式がそのメソッド自体の返り値になる。returnを利用した時点で返り値が決まるため、メソッドはその行までで強制的に終了する。
【例】returnを利用した場合
return文でメソッドは返り値を返してそのまま処理を終了する。return文のあとにコードがあっても無視される。
1 2 3 4 5 6 7 8 9 10 11 12 |
def sample
"1"
"2"
"3"
return "4" # ここで処理は終わり
"5" # 呼ばれない
"6" # 呼ばれない
end
puts sample # => 4
|
【例】returnを利用しない場合
Rubyではreturn文を省略することが可能。 return
を省略した場合、メソッドの返り値はそのメソッドの中で最後に実行された式の値となる。
1 2 3 4 5 6 7 8 9 10 |
def sample
"1"
"2"
"3"
"4"
"5"
"6" # 最後に実行されている
end
puts sample # => 6
|
Rubyでは、どんな記述も式と捉え、その返り値を持つ。上記のように文字列を書いておくだけの場合、返り値はその文字列の値となる。
本引数と仮引数の関係①
1 2 3 4 5 6 |
def mixer(fruit)
puts "#{fruit}を細かく砕く"
return "#{fruit}ジュース"
end
puts mixer("リンゴ") # => リンゴジュース
|
メソッドの呼び出し側で渡された引数(リンゴ)は引数を入れる変数(fruit)としてメソッド内で使うことができる。
6 |
puts mixer("リンゴ") # この"リンゴ"という値がメソッドmixerに渡される。
|
puts 〇〇 とすればputsに引数として渡した値が出力される。今、〇〇の部分がmixer("リンゴ")
となっている。そこでまずメソッドmixer自体の返り値(メソッド自体の答え)を確定させるために、メソッドmixerが実行される。
1 2 3 |
def mixer(fruit) # 渡された"リンゴ"という値が引数を入れる変数fruitに代入される。
puts "#{fruit}を細かく砕く" # 今、fruitには"リンゴ"という値が入っている。
return "#{fruit}ジュース" # "リンゴジュース" を返す。
|
以上より、mixer("リンゴ")は、"リンゴを細かく砕く"を出力した後、"リンゴジュース"を返り値とする。
1 2 3 4 5 6 |
puts mixer("リンゴ") # mixer("リンゴ")を出力するとその返り値である"リンゴジュース"が出力される
リンゴジュース
juice = mixer("ブドウ") # 変数に代入もできる
puts juice
=> ブドウジュース # puts juiceの実行結果
|
引数を使うと、渡す引数によって結果を変えることができるので非常に便利。6行目の「puts mixer("リンゴ") 」の"リンゴ"をいろんな文字列に変えると結果の出力も変わる。
本引数と仮引数の関係②
1 2 3 4 5 6 7 |
def rename(name)
name = "Mr.#{name}"
end
name = "Tanaka"
rename(name)
puts name
|
ここで定義しているメソッドrename
は引数で渡した変数name
にMr.をつけるという処理を行っている。しかし、実行してみるとわかるように7行目のputsではMr.TanakaではなくTanakaと表示される。
1 2 |
$ ruby sample.rb
Tanaka
|
引数で渡した値はメソッドで変数に入れられてメソッド内で使用される。このとき実は、メソッドの変数には引数で渡した値のコピーが代入されている。
引数のname
とrenameメソッドで受け取る変数name
を以下のように色分けして考える。
ここで重要なのは引数のname
とrename
メソッドで受け取る変数name
は名前は同じだが、別物であるということ
- まず、5行目で
name
に文字列"Tanaka"が代入される。
1 2 3 4 5 6 7 |
def rename(name)
name = "Mr.#{name}"
end
name = "Tanaka"
rename(name)
puts name
|
- 次にこの
name
を引数としてメソッドrenameを呼び出す。このときname
の中に入っている値がコピーされる。この場合、文字列"Tanaka"の値がコピーされる。
1 2 3 4 5 6 7 |
def rename(name)
name = "Mr.#{name}"
end
name = "Tanaka"
rename(name)
puts name
|
- コピーされた文字列"Tanaka"はメソッドrenameの変数
name
に代入される。よって、引数name
とメソッドで使われる変数name
の中身の値は同じになり、メソッドに値を渡すことができる。
1 2 3 4 5 6 7 |
def rename(name)
name = "Mr.#{name}"
end
name = "Tanaka"
rename(name)
puts name
|
- メソッド内の変数
name
の値を変えても、この変数と引数の変数name
は別物であるため引数の変数name
には影響を与えない。
1 2 3 4 5 6 7 |
def rename(name)
name = "Mr.#{name}"
end
name = "Tanaka"
rename(name)
puts name
|
よって、変数name
にMr.をつけるメソッドrename
は以下のようにすれば期待通りに動くようになる。
1 2 3 4 5 6 7 |
def rename(name)
name = "Mr.#{name}"
end
name = "Tanaka"
name = rename(name)
puts name
|
1 2 |
$ ruby sample.rb
Mr.Tanaka
|
メソッドrename
では引数から受け取ったname
にMr.をつけた文字列を返り値としてメソッドの呼び出し元に返す。
1 2 3 |
def rename(name)
name = "Mr.#{name}" # nameにMr.をつけた文字列をname自身に代入して、nameを返り値として返す
end
|
以前はrename(name)
と、単にメソッドrename
を呼び出しただけだったが、今回はname = rename(name)
とメソッドからの返り値をname
に代入している。
7 |
name = rename(name) # nameにrenameメソッドの返り値を代入
|
これで、name
の値が、メソッドrename
によってMr.をつけた文字列になります。