はじめに
はじめまして。自分はプログラミング初心者ですが、一つのプログラムを解いてみました。
その備忘録として本記事を書きます。
Qittaへの投稿は初めてであるため、お見苦しい点や至らない点等あるかとございますが、ご容赦ください。
参考や引用に使用させていただいたサイトは「終わりに」の部分にまとめてあります。
動作環境
本記事はRubyの環境で動作確認をしております。
また、自分は主にCloud9を使用してプログラムを実行しています。
この記事の方針
def rename(name)
name = "#{name}::CAMP"
return name
end
name = "TECH"
rename(name)
puts name
上記のプログラムの結果がどのような理由で出力されるのかを確認していく。
実行結果の分析
最終的な結果としてターミナルに出力されたのは以下のコードです。
TECH
この出力された値は「name = "TECH"」で「name」という変数に代入された「TECH」であろうことは何となく予想がつきます。
何故ならこれ以外にコード上に「TECH」という値が見当たらないからです。
主な問題は2点です。
1つは、renameメソッド内にある「name = "{name = #{name::CAMP}}"」という変数nameが出力には何も影響していないこと。
そしてもう1つが、「rename(name)」でrenameメソッドを呼び出しているにも関わらず、出力されていないこと。
スコープ
まず、1つ目の”renameメソッド内にある「name = "{name = #{name::CAMP}}"」という変数nameが出力には何も影響していない”という問題を解決するのに必要な知識がスコープです。
スコープとは何なのか、Wikipediaによると、
スコープとは、ある変数名や関数名といった名前を参照できる範囲のこと。ある範囲の外に置いた変数等は、通常、その名前だけでは参照できない。このときこれらの変数はスコープ外である、「見えない」といわれる。
この説明だとわかるようなわからんような、といったように感じます。
つまり、プログラミングでは変数や関数が使える範囲と使えない範囲が存在するということだと自分は認識しています。
この「変数や関数が使える範囲」のことが「スコープ」であるというイメージです。
本記事のコードで具体的に見て行きましょう。
def rename(name)
name = "#{name}::CAMP" #この変数nameはrenameメソッド内でしか使用できない。
return name
end
name = "TECH" #この変数nameはこの行より下ならどこでも使える。
rename(name)
puts name
上記のコードのコメントで書いたとおり、本記事のコードの場合、renameメソッド内の変数nameはrenameメソッド内でしか使えません。
ついでに言うとrenameメソッドの引数nameもrenameメソッド内でしか使えません。
正確には、ブロック内で定義された値はそのブロック内でしか使用できません。
このようなスコープはローカルスコープと呼ばれているようです。
また、本記事のコードの場合、スコープ外で定義された変数は、定義された位置より下ならどこでも使用が可能です。
この変数nameは関数の内側でも、外側でも関係なく使用できます。
実際に確かめてみましょう。本記事のコードを以下のように書き換えて実行してみます。
def rename(name)
name1 = "#{name}::CAMP"
return name
end
name2 = "TECH"
rename(name2)
puts name1
プログラムを実行するとエラーメッセージが出力されると思います。
これは先ほど説明した通り、renameメソッド内の変数name1はrenameメソッド外では使用できないからです。
では、「puts name1」を「puts name2」に変更してプログラムを実行してみましょう。
TECH
上記のように出力されるはずです。
これで、なぜrenameメソッド内の変数nameが出力には影響しなかったのかが理解できたかと思います。
実際にコードを書く際は予期しない動作を避けたり、コードの読みやすさを重視するためにスコープの範囲はできるだけ小さくしたほうがいいと思います。
また、スコープにもいくつか種類があるので、Wikipedia等を参照してください。
戻り値
さて、もう1つの「rename(name)」でrenameメソッドを呼び出しているにも関わらず、出力されていない、という問題を解決していきましょう。
コードをもう一度確認してみましょう。
def rename(name)
name = "#{name}::CAMP"
return name
end
name = "TECH"
rename(name)
puts name
先ほど変数nameを「name1」や「name2」にしていましたが、すべて「name」に直しました。
まず、renameメソッドがどういった処理が行われているのか確認していきましょう。
renameメソッドは引数を受け取り、受け取った引数を利用して変数nameを定義し、定義した変数nameを「return」でrenameメソッドが呼び出された場所に戻す処理が行われています。
この時に変数nameが戻り値になります。
戻り値とは何なのかIT用語辞典 e-Wordsによると、
戻り値とは、プログラム中で呼び出された関数やメソッド、サブルーチンなどが処理を終了する際に、呼び出し元に対して渡す値。
何となくこの説明でも理解はできますが、かみ砕いて要約すると”関数等で呼び出し元に「return 値」で指定した値を渡す”といった感じでしょう。
実際に本記事のコードで確認してみましょう。
def rename(name)
name = "#{name}::CAMP"
return name #変数nameという値をrenameメソッドの呼び出し元に渡す。
end
name = "TECH"
rename(name) #renameメソッドの呼び出し元。
#renameメソッド内で定義された変数nameがここに渡される。
puts name
上記のコードのコメント部分に書いた通り、「rename(name)」はrenameメソッド内で定義された変数nameの値になる。
なのになぜ、ターミナルには出力されないのか。
これは「return」は値を呼び出し元に返しているだけで、出力するという命令はしていないからです。
もし、本記事のコードでrenameメソッドの戻り値をターミナルに出力しようとした場合、「rename(name)」のコードを「puts rename(name)」に書き換えましょう。
すると、以下のコードが出力されるはずです。
TECH::CAMP
TECH
戻り値をターミナルに表示したい場合は、出力を命令するコードを書くことに気を付けましょう。
まとめ
本記事のコードの実行結果が「TECH」という値しかターミナルに表示されない理由は、
-
renameメソッド内で定義された変数nameは、スコープによってrenameメソッド外では使えないため、本記事のコードの「puts name」の部分には全く関係しないこと。
-
戻り値は呼び出し元に「return 値」で指定した値を渡せるが、出力を命令するコードがないとターミナルには表示されないこと。
という2点であるというわけです。
終わりに
最後まで自分の稚拙な記事を読んでいただきありがとうございました。
間違いや良くない点等多々あったかと思いますが、一応1つの記事を書き上げることができました。
次の機会があれば、本記事を書いて得た経験を活かしてより良い記事を作りたいと思います。
最後に引用に使ったり、参考にさせて頂いたサイトをまとめておきます。
スコープ - Wikipedia