読んでほしい人
インスタンス変数の意味はなんとなくわかったけど、結局どうローカル変数・インスタンス変数・クラス変数を使い分けるの?
という過去の自分のような人へ。
初学者でもこれさえ読めばわかるように書けていると思います。
結論:スコープです
どこの範囲で使いたい変数なのかを考えましょう。
つまりスコープ(変数やメソッドを呼び出せる範囲)を考えればよいのです。
可読性やインスタンスとは、を考えるとこれだけではないのですがスコープの違いを理解すればひとまず動くコードが書けます。
以下で解説します。
Rubyで使える変数の種類
1.ローカル変数
2.インスタンス変数
3.クラス変数
(4.クラスインスタンス変数)
5.グローバル変数
それぞれスコープが違います。
ローカル変数
変数名の前に@も何もつけません。定義したメソッドやクラスの中だけで呼び出せます。
スコープ外で呼び出そうとするとundefined local variable or method `〇〇〇' for main:Object (NameError)
というエラーが出ます。
例1 変数morningはmorning_messageメソッドの中だけで使える
def morning_message
morning = "朝"
puts "#{morning}です"
end
morning_message # => 朝です
puts morning # => undefined local variable or method `morning' for main:Object (NameError)
例2 クラス内に直接定義した場合はMorningクラスの中かつself.messageの外側だけで使える
class Morning
morning = "朝"
def self.message
puts "#{morning}です"
end
self.message # => undefined local variable or method `morning' for Morning:Class (NameError)
end
インスタンス変数
頭に@をつけます。同じクラスのインスタンスメソッドの中ならどこでも呼び出せます。
initializeメソッド以外で定義することもできます。
スコープ外で呼び出そうとするとnilが返ってきます。
例1 initializeメソッドで定義した@color
をput_colorメソッドでも使える
class Color
def initialize(color)
@color = color
end
def put_color
puts @color
end
end
color1 = Color.new("青")
color1.put_color # => 青
p @color # => nil
例2 initializeメソッド以外でもインスタンス変数を定義
class Color
def initialize(color)
@color = color
end
def decide_rank
if @color == "青"
@rank = "A"
elsif @color == "赤"
@rank = "B"
end
end
def explain
puts "#{@color}のランクは#{@rank}です"
end
end
color1 = Color.new("青")
color2 = Color.new("赤")
color1.decide_rank
color1.explain # => 青のランクはAです
color2.decide_rank
color2.explain # => 赤のランクはBです
クラス変数
頭に@@をつけます。クラス内のどこでも呼び出せます。
インスタンス変数はインスタンスごとに別々の値になるのに対して、クラス変数はクラス内で共通の値になります。
スコープ外で呼び出そうとするとuninitialized class variable @@〇〇〇 in Object (NameError)
というエラーが出ます。
例 @@monitor
はcolor1,2で共通
class Color
@@monitor = "モニター1"
def initialize(color)
@color = color
end
def rank
if @color == "青"
@rank = "A"
elsif @color == "赤"
@rank = "B"
end
end
def explain
puts "#{@@monitor}の#{@color}のランクは#{@rank}です"
end
end
color1 = Color.new("青")
color2 = Color.new("赤")
color1.rank
color1.explain # => モニター1の青のランクはAです
color2.rank
color2.explain # => モニター1の赤のランクはBです
puts @@monitor #=> uninitialized class variable @@monitor in Object (NameError)
クラスインスタンス変数
インスタンス変数の一種で、クラス自身が持つ(=クラス内に直接定義されている)インスタンス変数のことです。
なので同じく頭に@をつけます。普通のインスタンス変数との違いは定義場所とスコープです。
インスタンス変数と違って子クラスから参照できません。(インスタンスメソッドとクラスメソッドの違いに起因)
例 クラスインスタンス変数は子クラスから参照できない
class Color
@color = "青"
def self.put_color
puts @color
end
end
class DarkColor < Color
def self.put_dark_color
puts "濃い#{@color}"
end
end
Color.put_color # => 青
DarkColor.put_dark_color # => 濃い ・・・青が出力されていない
グローバル変数
頭に$をつける。プロジェクト内ならどこでも呼び出せます。
スコープが広すぎるがゆえに意図せず変数名が被り、内容が書き換えられてしまうことがあるので、どうしてもというときだけ使うようにしましょう。
例 $brightnessがどこでも呼び出せる&書き換えられる
$brightness = 2000
class Color
def initialize(color)
@color = color
end
def explain
puts "その#{@color}の輝度は#{$brightness}ntです"
end
end
color1 = Color.new("青")
color2 = Color.new("赤")
color1.explain # => その青の輝度は2000ntです
$brightness = 100000
color2.explain # => その赤の輝度は100000ntです
まとめ
インスタンス変数の使いどころが理解できていない人は
- スコープを意識
- リファクタリング(可読性・保守性向上)
の順番で考えてみるのが良いと思います。
さいごに
この記事についての感想・意見・指摘などあれば伝えて頂けると嬉しいです。
参考元
https://techacademy.jp/magazine/9704
https://qiita.com/tomokichi_ruby/items/a2548176d85457f622a4
https://qiita.com/shun_takagi/items/cba48fbe8c4de81b3fac
http://simanman.hatenablog.com/entry/2013/03/11/210756