はじめに
プログラミング初学者のものです。
Rubyを学習するにあたりグローバル変数とローカル変数の違いについてしっかり理解できていなかったのでまとめようと思います。
間違っているところがあれば教えていただけると嬉しいです。
グローバル変数とは
複数のサブルーチン(関数)間で値を共有できる変数です。
アプリケーションの開始から終了まで変数に入れた値を保持します。
ここでサブルーチンとはRubyでいうメソッドなどのある処理のまとまりのことを指します。
サブルーチンはメインルーチンから呼び出されることで処理が実行されます。
グローバル変数の特徴について2つ説明したいと思います。
- メインルーチンからサブルーチンを呼び出しサブルーチンで定義されている変数を参照することが可能。
- サブルーチンAとサブルーチンBで同じグローバル変数を定義したときに同じ参照を持つ変数になる。
グローバル変数はどこからでもアクセスができるため保守などが難しくなるなどの特徴もあります。
以下で具体例を用いて説明します。
以下では、$で始まる変数名でグローバル変数を定義しています。
$global_variable = 5
def function_a
x = $global_variable
puts x.object_id
end
# 関数B
def function_b
y = $global_variable
puts y.object_id
end
# メインルーチン
# メインルーチンからでも変数にアクセスできる。
function_a
function_b
# 結果
11
11
1について、関数Aと関数Bで定義されているグローバル変数global_variableは同じメモリの参照を持つことになります。
2についてメインルーチンからでもサブルーチンを呼び出すことができています。
ローカル変数とは
先ほどはグローバル変数の場合を説明しましたがローカル変数ではどうなるのでしょうか。
ローカル変数とは1つのサブルーチンからしかアクセスできない変数のことです。
サブルーチンを呼び出した時に作られてサブルーチンを抜ける時に破棄されます。
以下でグローバル変数とローカル変数の違いを説明します。
例1
local_variable = 5
def function_a
x = local_variable
end
# 関数B
def function_b
y = local_variable
end
# メインルーチン
function_b
# メインルーチンから変数にアクセスできない。
エラー:Main.rb:9:in `function_b': undefined local variable or method `local_variable' for main:Object (NameError)
y = local_variable
^^^^^^^^^^^^^^
Did you mean? local_variables
global_variables
from Main.rb:14:in `<main>'
ローカル変数で定義するとグローバル変数で定義したときに比べて上記の例のように以下の2つの違いがあります。
- メインルーチンからはサブルーチンで定義した変数にアクセスできないためメインルーチンからローカル変数を定義したサブルーチンを呼び出そうとするとエラーが出る。
- サブルーチンをでたらメソッドのメモリは解放されるため関数Aと関数Bにおいてlocal_variableで示されるローカル変数は同じ参照を保持しない。次回関数呼び出し時に再度初期化されメモリが配置される。
またメソッド内のローカル変数に代入してもメソッド外で定義した変数に影響しません。
local_variable = 5 # メイン処理のローカル変数
def function_a
local_variable = 10 # function_aのローカル変数
puts local_variable
end
# メイン処理
function_a
puts local_variable
10
5
ではメソッド間で値を共有したいときはどうすれば良いのでしょうか。
以下のように引数を使った方法なら関数Aで参照している変数を関数Bで参照できるようになります。
#ローカル変数の初期化
#ローカル変数の初期化
local_variable = 10
# 関数A
def function_a(local_variable)
local_variable += 5
end
# 関数B - 関数Aを呼び出す
def function_b(local_variable)
function_a(local_variable)
end
インスタンス変数とは
ここまででグローバル変数とローカル変数の違いについて説明してきましたが、インスタンス変数についてもまとめていきたいと思います。
インスタンス変数とは存在期間が長い(サブルーチンを抜けても変数のために確保したメモリが解放されない)というグローバル変数のいいところと影響範囲を局所化できる(変数を定義したサブルーチンからでしか値にアクセスできない)というローカル変数のいいところを取って合わせたような変数です。
インスタンス変数とは同じクラス内のメソッドからのみアクセスができる変数です。
またインスタンス変数はインスタンスが作られてから必要がなくなるまで値を保持します。
以下でグローバル変数、ローカル変数、インスタンス変数の特徴をまとめたいと思います。
グローバル変数 | ローカル変数 | インスタンス変数 | |
---|---|---|---|
複数サブルーチンからのアクセス | できる | できない | できる |
アクセス可能範囲の限定 | プログラムのどこからでもアクセスできる | 1つのサブルーチンからしかアクセスできない | 同じクラス内のメソッドからのみアクセス可能 |
存在期間の長さ | アプリケーションの開始から終了まで | サブルーチンに呼び出し時に作られて抜ける時に破棄される | インスタンスが作られてから必要なくなるまで |
インスタンス変数は違うメソッド間でもアクセスが可能な例を以下で示します。
class User
def initialize
@is_logged_in = false
end
def login
@is_logged_in = true
puts @is_logged_in.object_id
end
def logout
@is_logged_in = false
puts @is_logged_in.object_id
end
def is_logged_in
@is_logged_in
puts @is_logged_in.object_id
end
end
# メインルーチン
tanaka = User.new
tanaka.login
tanaka.is_logged_in
# 結果
20
20
# メインルーチン
tanaka = User.new
tanaka.login
tanaka.logout
# 結果
20
0
スコープという概念について
グローバル変数とローカル変数をどのようにして実現しているのか気になったので少し調べてみました。
グローバル変数はヒープ領域という部分に格納され、
ローカル変数はスタックフレームという箇所に格納されるらしいです。
この低レイヤーでの動きはまだ全然理解できていないのでおいおい理解していきたいと思います。