サーチ…


構文

  • $ global_variable
  • @@ class_variable
  • @インスタンス変数
  • local_variable

備考

クラス変数はクラス階層で共有されます。これは驚くべき振る舞いにつながります。

class A
  @@variable = :x

  def self.variable
    @@variable
  end
end

class B < A
  @@variable = :y
end

A.variable  # :y

クラスはオブジェクトなので、インスタンス変数を使用して各クラスに固有の状態を提供することができます。

class A
  @variable = :x

  def self.variable
    @variable
  end
end

class B < A
  @variable = :y
end

A.variable  # :x

ローカル変数

ローカル変数(他の変数クラスと違って)には接頭辞がありません

local_variable = "local"
p local_variable
# => local

そのスコープは宣言された場所に依存し、 "宣言コンテナ"スコープの外では使用できません。たとえば、ローカル変数がメソッド内で宣言されている場合は、そのメソッド内でのみ使用できます。

def some_method
    method_scope_var = "hi there"
    p method_scope_var
end

some_method
# hi there
# => hi there

method_scope_var
# NameError: undefined local variable or method `method_scope_var'

もちろん、ローカル変数はメソッドに限定されず、 do ... endブロックの中に変数を宣言するか、中括弧{}で囲むとすぐに、それはローカルとスコープになりますそれが宣言されたブロック

2.times do |n|
    local_var = n + 1
    p local_var
end
# 1
# 2
# => 2

local_var
# NameError: undefined local variable or method `local_var'

しかし、 ifまたはcaseブロックで宣言されたローカル変数は、親スコープで使用できます。

if true
    usable = "yay"
end

p usable
# yay
# => "yay"

ローカル変数は宣言ブロックの外では使用できませんが、ブロックに渡されます。

my_variable = "foo"

my_variable.split("").each_with_index do |char, i|
    puts "The character in string '#{my_variable}' at index #{i} is #{char}"
end
# The character in string 'foo' at index 0 is f
# The character in string 'foo' at index 1 is o
# The character in string 'foo' at index 2 is o
# => ["f", "o", "o"]

しかし、メソッド/クラス/モジュールの定義ではない

my_variable = "foo"

def some_method
    puts "you can't use the local variable in here, see? #{my_variable}"
end

some_method
# NameError: undefined local variable or method `my_variable'

ブロック引数に使用される変数は、(もちろん)ブロックに対してローカルですが、上書きすることなく、以前に定義された変数を覆い隠してしまいます。

overshadowed = "sunlight"

["darkness"].each do |overshadowed|
    p overshadowed
end
# darkness
# => ["darkness"]

p overshadowed
# "sunlight"
# => "sunlight"

クラス変数

クラス変数はクラスワイドスコープを持ち、クラス内のどこにでも宣言することができます。変数は、接頭辞@@ときにクラス変数と見なされます

class Dinosaur
    @@classification = "Like a Reptile, but like a bird"
    
    def self.classification
        @@classification
    end

    def classification
        @@classification
    end
end

dino = Dinosaur.new
dino.classification
# => "Like a Reptile, but like a bird"
  
Dinosaur.classification
# => "Like a Reptile, but like a bird"

クラス変数は関連クラス間で共有され、子クラスから上書きできます

class TRex < Dinosaur
    @@classification = "Big teeth bird!"
end

TRex.classification
# => "Big teeth bird!"

Dinosaur.classification
# => "Big teeth bird!"

この動作はほとんどの場合不要であり、クラスレベルのインスタンス変数を使用することで回避できます。

モジュール内で定義されたクラス変数は、そのクラスを含むクラス変数を上書きしません。

module SomethingStrange
    @@classification = "Something Strange"
end

class DuckDinosaur < Dinosaur
    include SomethingStrange
end

DuckDinosaur.class_variables
# => [:@@classification]
SomethingStrange.class_variables
# => [:@@classification]

DuckDinosaur.classification
# => "Big teeth bird!"

グローバル変数

グローバル変数はグローバルなスコープを持つため、どこでも使用できます。スコープは、定義されている場所に依存しません。 $記号が前に付いた変数は、グローバル変数と見なされます。

$i_am_global = "omg"

class Dinosaur
    def instance_method
       p "global vars can be used everywhere. See? #{$i_am_global}, #{$another_global_var}" 
    end

    def self.class_method
       $another_global_var = "srsly?"
       p "global vars can be used everywhere. See? #{$i_am_global}"
    end
end

Dinosaur.class_method
# "global vars can be used everywhere. See? omg"
# => "global vars can be used everywhere. See? omg"

dinosaur = Dinosaur.new
dinosaur.instance_method
# "global vars can be used everywhere. See? omg, srsly?"
# => "global vars can be used everywhere. See? omg, srsly?"

グローバル変数はどこにでも定義でき、どこでも見ることができるので、 "未定義"グローバル変数を呼び出すと、エラーを発生させる代わりにnilが返されます。

p $undefined_var
# nil
# => nil

グローバル変数は使いやすいですが、定数の使用を強くお勧めします。

インスタンス変数

インスタンス変数にはオブジェクトのスコープがあり、オブジェクトのどこにでも宣言できますが、クラスレベルで宣言されたインスタンス変数はクラスオブジェクトでのみ表示されます。 @接頭辞が付いた変数はインスタンス変数と見なされます。インスタンス変数は、オブジェクトの属性を設定および取得するために使用され、定義されていない場合はnilを返します。

class Dinosaur
    @base_sound = "rawrr"

    def initialize(sound = nil)
        @sound = sound || self.class.base_sound
    end

    def speak
        @sound
    end

    def try_to_speak
        @base_sound
    end

    def count_and_store_sound_length
        @sound.chars.each_with_index do |char, i|
            @sound_length = i + 1
            p "#{char}: #{sound_length}"
        end
    end
    
    def sound_length
        @sound_length
    end

    def self.base_sound
        @base_sound
    end
end

dino_1 = Dinosaur.new
dino_2 = Dinosaur.new "grrr"

Dinosaur.base_sound
# => "rawrr"
dino_2.speak
# => "grrr"

クラスレベルで宣言されたインスタンス変数は、オブジェクトレベルではアクセスできません。

dino_1.try_to_speak
# => nil

しかし、新しいメソッドにサウンドが渡されないときにインスタンス変数@base_soundを使用してサウンドをインスタンス化しました。

dino_1.speak
# => "rawwr"

インスタンス変数は、たとえブロック内であっても、オブジェクト内のどこにでも宣言することができます。

dino_1.count_and_store_sound_length
# "r: 1"
# "a: 2"
# "w: 3"
# "r: 4"
# "r: 5"
# => ["r", "a", "w", "r", "r"]

dino_1.sound_length
# => 5

インスタンス変数は、同じクラスのインスタンス間で共有されません

dino_2.sound_length
# => nil

これは、クラスがRubyのオブジェクトでもあるため、子クラスによって上書きされないクラスレベルの変数を作成するために使用できます。

class DuckDuckDinosaur < Dinosaur
    @base_sound = "quack quack"
end

duck_dino = DuckDuckDinosaur.new
duck_dino.speak
# => "quack quack"
DuckDuckDinosaur.base_sound
# => "quack quack"
Dinosaur.base_sound
# => "rawrr"


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow