56
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

rubyの変数について

Last updated at Posted at 2016-08-30

久しぶりにrubyを触り、曖昧な部分が曖昧すぎたので整理しようと思います。

##最初に
今回調べるにあたったきっかけが「インスタンス変数って @マークいるよね?」というところで、そこからインスタンスメソッド、クラス、クラスメソッド、、、などなどどんどん横道に逸れていき、結局わからなくなってしまった。
なので最初に書いておきたいこととして、

インスタンス「変数」とインスタンス「メソッド」は全く別物として考えましょう

ということですね。
今回取り上げるのが

・ローカル変数
・インスタンス変数
・クラス変数
・クラスインスタンス変数

ですが、上記を調べてたら出てきそうなインスタンスメソッドとかは一旦無視します。
なんならここが一番言いたいのかもしれない

##一言で言うと
では上記4つの変数の違いってなんやねん?ということですが、変数っていうくくりで考えたら至極当たり前なことで

「スコープの違い」

以上です。それ以上でも以下でもないです。
なんてことはないんですが、僕みたいな人間はすぐごっちゃ混ぜにするので気をつけます。
では見ていきます。

##ローカル変数

書き方:小文字または_ではじめる。
スコープ:そのメソッド
定義:変数が宣言されたブロック、メソッド定義、またはクラス/モジュール定義の終わりまで。つまり、オブジェクトの壁やメソッドの壁を超えては参照できず、それが定義された場所でしか通用しない

例えば
1)メソッドの中でローカル変数を作ってみたとする

//変数なし
class Foo
  def hoge
    p 'aaa'
  end
end

poo = Foo.new
poo.hoge
=>"aaa"
//メソッド内にローカル変数、メソッド内でprint
class Foo
  def hoge
    bbb = 'aaa'
    p bbb
  end
end

poo = Foo.new
poo.hoge
=> "aaa"
//ローカル変数をクラス内に定義、メソッドから呼び出し
class Foo
  foo = 'aaa'
  def hoge
    p foo
  end
end

poo = Foo.new
poo.hoge
=> `hoge': undefined local variable or method `foo' for #<Foo:0x007fcf82932908> (NameError)

なんとまぁ。同じクラスの中にいる変数でも、メソッドの中で使えないと。。。

##インスタンス変数
書き方 : @を前置する
スコープ:クラス内で全メソッドで共通して使用することが出来る。クラスから作成されるオブジェクト毎に固有のもの。このようにインスタンスごとに独立してもつ変数だから、インスタンス変数という。

// initializeで初期値@fooをFooクラスに作成
class Foo
  def initialize
    @foo = 'aaa'
  end

  def huga
    @foo
  end
end

poo = Foo.new
p poo.huga
=> "aaa"

initialize@fooをきちんとメソッドhugaが受け継いでいるので、aaaが表示されてますね。
どんどん見てみます。

class Foo
  def initialize
    @foo = 0
  end

  def increment
    @foo += 1
  end

  def foo
    @foo
  end
end

poo1 = Foo.new
p poo1.increment

poo2 = Foo.new
p poo2.increment
=>1
=>1

これは分かりやすいですね。
poo1,poo2で2つFooクラスを呼び出しているんで、それぞれ1が入ってますね。

class Foo
  def initialize
    @foo = 0
  end

  def increment
    @foo += 1
  end

  def foo
    @foo
  end
end

poo = Foo.new
p poo.increment
p poo.foo
=> 1
=> 1

あれ、、、poo.fooが0じゃない。。。?initializeの @foo = 0が入るのでは。。?
これは先にpoo.incrementを宣言したことで、Fooクラスの @fooに1が代入された状態で、
poo.fooを呼び出したため。なので,

class Foo
  def initialize
    @foo = 0
  end

  def increment
    @foo += 1
  end

  def foo
    @foo
  end
end

poo = Foo.new
p poo.foo
=> 0

だし、

class Foo
  def initialize
    @foo = 0
  end

  def increment
    @foo += 1
  end

  def foo
    @foo
  end
end

poo = Foo.new
p poo.increment
poo = Foo.new
p poo.foo
=> 1
=> 0

になります。Fooクラスを一度初期化してるので。
インスタンス変数は同一クラス内だとメソッド間で共有できる+上から順に実行していった値を保持しているってことですね。当然new をし直すとクラスが初期化されるので、同じ値をもたせたくないときにはnewすればよい。

##クラス変数
あんまり使わないそう。一応。
書き方:@@を前置
スコープ:そのクラスおよびそこから生成されるオブジェクト(インスタンス)の中ならどこからでも参照可能。

class Bar
  @@bar = 0

  def increment
    @@bar += 1
  end

  def bar
    @@bar
  end
end

bar = Bar.new
p bar.bar
p bar.increment
=> 0
=> 1

おお。。。initializeで初期化してるわけでもないんですが、普通にメソッドの中で使えますね。。。
ただ使わないと言われている理由が下記の例になります。

class Bar
  @@bar = 0

  def increment
    @@bar += 1
  end

  def bar
    @@bar
  end
end

bar1 = Bar.new
p bar1.increment
bar2 = Bar.new
p bar2.increment
=>1
=>2

え。。。。?いやいやどゆこと、、?
そうなのです。クラス変数は全部共通で使われちゃうんです。一回格納したら別のインスタンスでもその値を継承しちゃうという、、、

class Bar
  @@bar = 0

  def increment
    @@bar += 1
  end

  def bar
    @@bar
  end
end

bar1 = Bar.new
p bar1.increment
bar1 = Bar.new
p bar1.increment
=>1
=>2

そしてこれも、、、なんとnewをしてるのに初期化されない、、、どうやって使うんやこれは。。。

##クラスインスタンス変数
定義:変数名の前に「@」をつけて定義する
※ 見た目はインスタンス変数と同じだが、定義する場所がクラス定義式内になる

ローカル変数を見たときに

class Foo
  foo = 'aaa'
  def hoge
    p foo
  end
end

poo = Foo.new
poo.hoge

こういうのがありました。「あれ、じゃあこのローカル変数をインスタンス変数にしたらどうなるんや?」と思ってしまいました。

class Foo
  @foo = 'aaa'
  def hoge
    p @foo
  end
end

poo = Foo.new
poo.hoge
=> nil

むむ、、、この@fooはどうやって参照するんや。。

class Foo
  @foo = 'aaa'

  def hoge
    p @foo
  end

  def self.huga
    @foo
  end
end

p Foo.huga
=> "aaa"

ほう、、、こうやってすれば取り出せると、、、
クラスの中に、クラスメソッドを定義してあげればクラスインスタンス変数が取り出せる。。

そろそろまとめに

class Buzz
  @buzz = 0

  def self.buzz
    @buzz
  end

  def initialize
    @buzz = 10
  end

  def buzz
    'aaa'
  end

  def buzz2
    @buzz
  end
end

p Buzz.buzz

foo1 = Buzz.new
p foo1.buzz2

foo2 = Buzz.new
p foo2.buzz

=>0
=>10
=>"aaa"

initializeでインスタンス変数呼び出してるので若干わかりにくくなってます。
initializeのインスタンス変数を取り出すにはクラス内にメソッドを定義して呼び出してあげないといけないので、def buzz2で呼び出してます。(いわゆるゲッターってやつ?)

その他はご覧の通り。クラスインスタンス変数は p Buzz.buzzできちんと呼ばれてますね。
また@buzzがクラスインスタンス変数とインスタンス変数で呼ばれてますが、それぞれきちんと別の値が入ってます。

以上のように各変数でスコープ、いわゆる適応される範囲が違うってことですね。
これでどの値が入ってるねん!っていう疑問はなくなるかと。

次はゲッター、セッター、クラスメソッド、インスタンスメソッドあたりを攻めたいですね。

##参考
http://qiita.com/mogulla3/items/cd4d6e188c34c6819709
http://qiita.com/mogulla3/items/cd4d6e188c34c6819709

56
59
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
56
59

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?