Rubyの変数には、その変数を参照したり変更できる範囲(スコープ)が設定されている。
範囲の外からはその変数を利用できないので注意が必要。
個人的にその辺りではまったので、Rubyの変数スコープをおさらいする。
対象の変数は以下の5つ
- クラス変数
- インスタンス変数
- クラスインスタンス変数(=Classオブジェクトのインスタンス変数)
- ローカル変数
- グローバル変数
###用語
クラス定義内:class ~ endまでのブロックの中で、関数定義ブロック(def~end)を含まない領域とする。
##クラス変数
###定義の仕方
@@変数名で定義する
クラス定義内・クラスメソッド内・initializeメソッド内・インスタンスメソッド内でも定義できる
@@classname = xxxx
###スコープ
以下の範囲内で参照・更新が可能
・インスタンスメソッド
・クラスメソッド
・クラス定義内
・initializeメソッド
=>つまり、クラス内ならどこでも参照・定義・更新できる。
=> ただし、クラスを超えた参照はできない。(継承させるとできる)
実際に記述して見た
class Car
#クラス変数を定義
@@number_of_tire = 4
# (1) インスタンスメソッド内でクラス変数を呼び出す
def from_instance_method
p @@number_of_tire
end
# (2) クラスメソッド内でクラス変数を呼び出す
def self.from_class_method
p @@number_of_tire
end
# (3) initializeメソッド内でクラス変数を呼び出す
def initialize
p @@number_of_tire
end
# (4)クラス定義内でクラス変数を呼び出す
p @@number_of_tire # => 4 成功
end
#インスタンスを作成(initializeメソッドを実行)
car = Car.new # =>4 成功
#インスタンスメソッドを実行
car.from_instance_method # =>4 成功
#クラスメソッドを実行
Car.from_class_method # => 4 成功
##インスタンス変数
###定義の仕方
@変数名で定義する
インスタンスメソッドかinitializeの中で定義する!!
クラス定義内で定義すると、クラスインスタンス変数という別の変数になり動作が異なる
@variable_name = xxxx
###スコープ
以下の範囲内で参照・更新が可能
・インスタンスメソッド
・initializeメソッド
実際に記述してみる
class Car
# (1) initializeメソッド内でインスタンス変数を定義+呼び出し
def initialize
@car_name = "lexus"
p @car_name
end
# (2) インスタンスメソッド内でインスタンス変数を再定義+呼び出し
def from_instance_method
@car_name = "prius"
p @car_name
end
# (3) クラスメソッド内でインスタンス変数を呼び出す
def self.from_class_method
p @car_name
end
# (4)クラス定義内でインスタンス変数を呼び出す
p @car_name #=> nil 失敗
end
#インスタンスを作成(initializeメソッドを実行)
car = Car.new # => "lexus" 成功
#インスタンスメソッドを実行
car.from_instance_method #=> "prius" 成功
#クラスメソッドを実行
Car.from_class_method #=> nil 失敗
###考察
クラス定義内からも呼び出せなかった。
やはり、インスタンスメソッドとinitializeメソッドの外では利用できないということだろう。
##クラスインスタンス変数
##特徴
見た目はインスタンス変数だが、機能はクラス変数に近い。
クラス変数との違いは、
・継承しても利用できない
・インスタンスメソッドから利用できない
追記:クラスインスタンス変数という個別の変数があるわけではなく、要はClassクラスのオブジェクトが持つインスタンス変数らしいです。(ややこしいですが...)
なので、Carのインスタンスメソッド=クラス定義内のクラスメソッド では使えるのかと
参考)http://bambinya.hateblo.jp/entry/2016/01/10/151216
###定義の仕方
@変数名で定義する
※クラス定義内またはクラスメソッド内で定義する
※インスタンス/initializeメソッド内で定義すると、インスタンス変数として扱われるはず。
@variable_name = xxxx
###スコープ
以下の範囲内で参照・更新が可能
・クラスメソッド
・クラス定義内
実際に記述してみる
class Car
# (1)クラス定義内に変数を定義
@car_name = "lexus"
# (2) クラスメソッド内で変数を呼び出し
def self.from_class_method
p @car_name
end
# (3) initializeメソッド内で変数を呼び出す
def initialize
p @car_name
end
# (4) インスタンスメソッド内で変数を呼び出す
def from_instance_method
p @car_name
end
# (5) クラス定義内から呼び出し
p @car_name #=> "lexus" 成功
end
#クラスメソッドを実行
Car.from_class_method #=> "lexus" 成功
#インスタンスを作成(initializeメソッドを実行)
car = Car.new #=> nil 失敗
#インスタンスメソッドを実行
car.from_instance_method #=> nil 失敗
#クラスを継承させる
class Bike < Car
end
#継承先のクラスでクラスメソッドを実行
Bike.from_class_method #=> nil (変数呼び出し)失敗
###考察
上記には書いてないが、クラスメソッド内で定義をすると、継承先でも再定義されるようになった。
(再定義というよりは、継承したクラスメソッドの処理として新規で定義されているように思う)ので、少し注意が必要。
##ローカル変数
###定義の仕方
@無し、変数名のみで定義する
基本的にどこでも定義できる(はず)
variable_name = xxxx
###スコープ
以下の範囲内で参照・更新が可能
・定義した位置からその変数が定義されたブロック、メソッド、またはクラス/モジュール定義の終りまで。
=>ざっくり言うと、定義された場所の中だけで使える。メソッドを跨いだりすると使えない。
実際に記述してみる
class Car
# (1)クラス定義内にローカル変数を定義①
car_name = "lexus" #①
# (2) クラスメソッド内で①を呼び出し+ローカル変数を定義②
def self.from_class_method
p car_name #=> undefined local variable or method" ①の呼び出し失敗
class_defined = "at class" #②
end
# (3) initializeメソッド内で①を呼び出し+ローカル変数を定義③
def initialize
p car_name #=> undefined local variable or method" ①の呼び出し失敗
initialize_defined = "at initialize" #③
end
# (4) インスタンスメソッド内で①,②,③を呼び出し+ローカル変数を定義④
def from_instance_method
p car_name #=> undefined local variable or method" ①の呼び出し失敗
p class_defined #=> undefined local variable or method" ②の呼び出し失敗
p initialize_defined #=> undefined local variable or method" ③の呼び出し失敗
instance_defined = "at_instance" #④
end
# (5) 別のインスタンスメソッド内で④を呼び出し
def from_anoher_instance_method
p instance_defined #=> undefined local variable or method" ④の呼び出し失敗
end
# (5) クラス定義内から呼び出し
p car_name #=>"lexus" 成功
p class_defined #=> undefined local variable or method ②呼び出し失敗
p initialize_defined #=> undefined local variable or method ③呼び出し失敗
p instance_defined #=> undefined local variable or method ④呼び出し失敗
[1,2,3].each{p(car_name)} #=> "lexus" "lexus" "lexus" 成功
end
###考察
・クラス定義内で定義したローカル変数はクラスメソッド,インスタンスメソッド内で利用できない
・クラスメソッド、インスタンスメソッド内で定義したローカル変数は外のメソッドでは利用できない
=>やはり、定義された場所の中でしか利用できないことがわかった。
##グローバル変数
###定義の仕方
先頭に$+変数名で定義する
$variable_name = xxxx
###スコープ
プログラムのどこからでも参照できる。