変数のスコープについて、かなり単純なコードで説明したいと思う。
下記のようなコントローラーが記述されていたとする。
class SampleController < ApplicationController
def test1
sample_1 = 10
test3(sample_1)
end
def test2
sample_2 = 10
test4
end
private
def test3(num)
sample_3 = num + 10
end
def test4
sample_4 = sample_2 + 10
end
end
見たところ、test1アクションではプライベートメソッドのtest3(num)アクションを呼び出すことになり、test2アクションではプライベートメソッドのtest4アクションを呼び出すことになる。
結論から先に書くと、test1からのtest3(num)の呼び出しと処理は上手くいくが、test2からのtest4の呼び出しはできるが処理がうまくいかずエラーが出る。
#何が違うのか
####test1とtest3の場合
test1では、その内部でsample_1 = 10
と定義して、それを実引数としてtest3(sample_1)
という書き方でtest3(num)に渡している。
def test1
sample_1 = 10
test3(sample_1)
end
test3内部では、渡されたsample_1が仮引数であるnumに代入される。つまりわかりやすく(?)書くとnum = 10
ということになる。
def test3(num)
sample_3 = num + 10
end
こうして無事にnumに数を引き渡せたのでtest3(num)の中身の計算は実質sample_3 = 10 + 10
となって、sample_3 = 20
となる。
####test2とtest4の場合
test2では、その内部でsample_2 = 10
と定義したあと、test4を呼び出している。
def test2
sample_2 = 10
test4
end
test4内部では、test2で定義されたsample_2 = 10
が使えるので、中身の計算は実質
sample_4 = 10 + 10
となるため、sample_4 = 20
とな・・・・・・らない。
###エラーが出ます
なぜか?
def test4
sample_4 = sample_2 + 10
end
実はtest4内部でsample_2が使えないからである。
いくらtest2内部でsample_2 = 10
と定義していようが、test4さんには関係ない事なのである。
これが変数のスコープと呼ばれる物。
結論から先に書けば、test4内部使える変数は
- test4で定義した変数、または
- test4を呼び出したtest2内部で定義されたインスタンス変数
なのである。(正確に言えば確かグローバル変数とかいうやつも使えたと思うが話がややこしくなるので省略)
ん?インスタンス変数?あれです、あの@ついたやつです。
というわけで、test4の中でsample_2 = 10
を使いたいなら
def test2
@sample_2 = 10
test4
end
っていう風に定義して、test4でも
def test4
sample_4 = @sample_2 + 10
end
っていう風に@をつけて呼び出してあげれば使うことができ、無事にsample_4 = 20
となる。