dポイントプレゼントキャンペーン実施中!

こんばんは。

変数について教えて下さい。
プログラム自体が初めてなので
「たのしい Ruby 第3版」を読んでいます。

ずっとインスタンスとオブジェクトの違いが曖昧なままです。

その本の「クラスとモジュール」という章にて
クラスを定義する構文。
インスタンス変数とローカル変数の違いですが、
以下の説明で一部理解できずにつまずいています。

――――――――――――
@ で始まる変数は インスタンス変数 といいます。
ローカル変数はメソッドごとに異なる変数として扱われますが、
インスタンス変数は同じインスタンス内であれば、
メソッド定義を超えてその値を参照したり、変更したりできます。
なお、初期化されていないインスタンス変数を参照すると
nil が得られます。
インスタンス変数は、インスタンスごとに違う値を持つことができます。
またインスタンス変数は、
インスタンスがある間は値を保持しておいて
何度でも利用することができます。
一方、ローカル変数はメソッド呼び出しごとに新しく割り当てられるため、
メソッドから抜けると値を忘れてしまいます。
――――――――――――

ここで分からないのは、

・ローカル変数が "メソッドごと" に異なる変数として扱われる
・インスタンス変数は同じ "インスタンス内" であれば、
メソッド定義を超えてその値を参照したり、変更したりできます

の部分です。

Webで検索してますが、
プログラミング経験ありを前提で書かれているような。
他の言語も知らないので分からない、そんなページが多いです。

人に聞くからには
自分でも頑張って理解できるように考えますので、
どうか回答よろしくお願いします。

A 回答 (5件)

こんにちは


これは実際にクラスを定義して説明しないと分かりにくいのかなと思います。
なので簡単なプログラムを書いてみました。
(段付けに全角のスペースを使用しているので実行させる場合は半角スペースに書き換えが必要です)

後半の# => の右に書いてあるのがプログラムを実行したときに表示される文字です。
-------------------------------
class Person
 def set_name(name)
  @name = name
  puts "Set @name : #{@name}"
 end

 def print_name
  puts "My name is #{@name}"
 end

 def set_age(age)
  var = age
  puts "Set age : #{var}"
 end

 def set_height(height)
  var = height
  puts "Set height : #{var}"
 end
end

taro = Person.new
taro.set_name("Taro") # => Set @name : Taro
taro.print_name # => My name is Taro
taro.set_age(20) # => Set age : 20
taro.set_height(170) # => Set height : 170

jiro = Person.new
jiro.set_name("Jiro") # => Set @name : Jiro
jiro.print_name # => My name is Taro
-------------------------------


前半でPersonというクラスを定義しています。このクラスでは4個のメソッドと、@nameというインスタンス変数、下の二つのメソッドではvarというローカル変数を使用しています。
このクラスの定義が、言い換えれば設計図になります。
例えば一つの自動車の設計図から実体としての自動車がいくつも製造できるように、クラスの定義からも実体をいくつも作ることができて、この実体をインスタンスと言います。では、実体としてのインスタンスが何処にできるかというとコンピュータのメモリ空間の中に作られるのですね。具体的にどうなっているかは、今のところはあまり気にする必要はありません。

ではクラスの定義(設計図)からどうやってインスタンス(実体)を作るのかというと、それが次のプログラム行になります。

taro = Person.new
jiro = Person.new

ここではtaroとjiroという二つのインスタンス(実体)を作っています。インスタンスの中にはクラスの定義のとおりに@nameというインスタンス変数が存在して、4個のメソッドが使用可能になります。また、taroとjiroはそれぞれ個別の実体になります。ですからそれぞれの中に存在するインスタンス変数@nameもそれぞれ別のものとなります。


ここで、taroというインスタンスをみましょう。

taro.set_name("Taro") # => Set @name : Taro
taro.print_name # => My name is Taro

taroインスタンスのset_nameメソッドを利用して、インスタンス変数@nameに"Taro"という値をセットしていますね。次にtaroインスタンスのprint_nameというメソッドを利用して@nameの値を読み出して表示しています。同じインスタンス内のあるメソッドで設定したインスタンス変数の値が、同じインスタンス内の別のメソッドで読むことができるということですよね。つまりインスタンス変数はインスタンスの中にメソッドとは関係なく存在して値が保持されるということです。これが「同じインスタンス内であればメソッド定義を越えてその値を保持したままでいられる」という意味です。


つぎにローカル変数についてですが、
ローカル変数というのはメソッドの実行開始時に、コンピュータのメモリ空間のどこかに生成されてメソッドに実行が終わると破棄されて存在しなくなってしまいます。

taro.set_age(20) # => Set age : 20
taro.set_height(170) # => Set height : 170

このプログラム行では各の行で、taroインスタンスのset_ageメソッドとset_heghtメソッドが実行して、それぞれのメソッドでvarというローカル変数が使用されています。
set_ageメソッド開始時に作られたvarというローカル変数はset_ageメソッド終了時に破棄されます。そしてset_heghtメソッド実行時にまた別に作られます。つまりset_ageメソッドで使用したローカル変数varとset_hetghtメソッドで使用されたローカル変数は同じ名前ですが、まったくの別物ということですね。
ですからインスタンス変数の様に、あるメソッドでセットした値を別のメソッドで読み取るということは当然できません。これが「ローカル変数がメソッドごとに異なる」の意味です。




> hello = "Hello, Ruby."
> p hello
> puts hello
> print hello
>
> どのメソッドでもローカル変数が持つ値は
> 変わらないと思っていたのですが。


この4行のhelloというローカル変数が、ひとまとめで見えない一つのメソッドの中に書かれていると考えてみて下さい。

def 見えないメソッド
 hello = "Hello, Ruby."
 p hello
 puts hello
 print hello
end

見えないメソッド開始時にhelloというローカル変数が作られて、見えないメソッド終了時にhelloというローカル変数は破棄されます。その間ではhelloは一つの変数として値を保持したまま存在します。



私も詳しく理解しているわけではありませんので、アバウトな説明になってしまいましたが、ご理解の一助にしていただければ幸いです。
    • good
    • 0
この回答へのお礼

回答ありがとうございます!

例え話はとても分かりやすいですね。
イメージではそれほど難しくなかったので、
言葉に表すととても長くなってしまい、
大変な思いをさせました。

本では、インスタンス変数を使うには
初期化しないと nil が返されると書かれています。
initialize メソッドで初期化するために
あなたが書いてくれたコードを
少し書き換えて実行してみたのですが、
ArgumentError となってしまいます。

また少し調べてみます。
ありがとうございました。

お礼日時:2012/08/25 21:42

こんにちは、No.2です。



> 本では、インスタンス変数を使うには
> 初期化しないと nil が返されると書かれています。

そうですね、@nameに値をセットしない(初期化しない)ままprint_nameメソッドを使用するとおかしなことになってしまいますね、失礼いたしました。
仰るとおり初期化をinitializeメソッドで行います。
(例によって段付けの為に全角スペースを使用しています)

class Person
 def initialize
  @name = "no name"
 end
 以下略
end

taro = Person.new
taro.print_name # => My name is no name


あるいはset_nameメソッドを使用しないでインスタンスを作るときに@nameを設定してしまう場合は以下のようになります。

class Person
 def initialize(name)
  @name = name
 end
 以下略
end

taro = Person.new("Taro")
taro.print_name # => My name is Taro



> ArgumentError となってしまいます。

下のinitializeメソッドの例やset_nameメソッドの様に丸括弧をつけてメソッドに与えるデータ(パラメータ)を引数(Argument)といいます。

taro = Person.new("Taro") 

の"Taro"の部分ですね。


ArgumentErrorとは引数が必要無いのにメソッドを実行するときに引数をつけた、引数が必要なのに引数をつけなかった、つけた引数の数が必要な数と一致しなかった場合などに発生します。


以上、本題とは外れてしまいましたが補足をさせていただきました。



最後にNo.2のプログラムの最終行は
jiro.print_name # => My name is Jiro
の誤りでした(表示する内容の誤り)、失礼致しました。
    • good
    • 0
この回答へのお礼

ArgumentError は、
インスタンスを作らずに
いきなりメソッドへ引数を渡してしまった
僕の間違いでした。

ありがとうございます。

お礼日時:2012/08/27 22:55

インスタンスとオブジェクトは同じ物です。

微妙なニュアンスは違いますが、プログラミング上は同じ物と思って大丈夫です。

>・ローカル変数が "メソッドごと" に異なる変数として扱われる

同じ変数名が異なるメソッドで使われていても、それは同じ物で無く、異なる変数であると言うことです。
同じ「太郎」でも、「鈴木家の太郎」と「田中家の太郎」は別人ということ。

>・インスタンス変数は同じ "インスタンス内" であれば、メソッド定義を超えてその値を参照したり、変更したりできます

もう少しわかりやすく書き直すと、
「同じオブジェクトのインスタンス変数は、そのオブジェクトに固有の物で、どのメソッドからも同じ物として参照・代入できます。もちろん、異なるオブジェクトの同名のインスタンス変数は別物です」
わかりやすくなってなかったらごめん。

インスタンス変数はオブジェクトの属性のようなものです。よく「自動車クラスの、個々の車がオブジェクト」とかいう例えがされますが、「ある車の色は、誰から見ても同じ色。違う車の色は、また違う(かもしれない)」ということです。

(こういう比喩は厳密には正しくないのであまり囚われないでください)
    • good
    • 0
この回答へのお礼

オブジェクトとインスタンスは意味は同じで
使い方が違うだけなのですね。

ローカル変数とインスタンス変数についても
他の方の回答があって
やっと理解できました。

ありがとうございます。

お礼日時:2012/08/27 22:50

言語によっては使いわけるものもあるかもしれませんが


Rubyではオブジェクトとインスタンスは同義です。



> 分かる人からすると、
> 言っている意味が分からない
> なんてことになるんでしょうね。

そういうことでは無いと思います。
どこまで理解できていて、どこが理解できていないのか、を明確にするのは、答える側にも、そしてなにより聞く側にも重要なことです。

ローカル変数/グローバル変数があることを理解していて、その上でインスタンス変数がわからないのか
ローカル変数/グローバル変数がそもそも理解できていないのか
で、答え方がぜんぜんちがいますから。

この回答への補足

なるほど。
ローカル変数とグローバル変数は分かります。

ローカル変数はアルファベット小文字およびアンダースコアで始まり、
数字を最初に置いてはいけない、と。

グローバル変数は$で始まり、
require メソッドで読み込むと参照・変更ができますね。

インスタンス変数は@で始まり、
class ~ end の中で使う
という事しか分かっていませんでした。

あとひとつ、
クラス変数は分かりません。

補足日時:2012/08/25 21:50
    • good
    • 0

どう「わからない」んでしょうか?

この回答への補足

すみません。

分かる人からすると、
言っている意味が分からない
なんてことになるんでしょうね。

まずインスタンスが何なのかさえ分かりません。

インスタンスはオブジェクトと
同じ意味ではありませんね?

@で始まるものを
インスタンス変数と呼ぶのは分かりますが、
インスタンスという言葉がついてる以上、
インスタンスに関わる性質を持っていると思います。
→でも「インスタンス」が分からない。

インスタンス変数が
同じインスタンス内であれば
メソッド定義を越えて
その値を保持したままでいられるとは、
何のことでしょうか。
→「インスタンス内」とは何かのブロック?

ローカル変数がメソッドごとに異なるとは、
どういう意味で何が異なるんでしょうか。

hello = "Hello, Ruby."
p hello
puts hello
print hello

どのメソッドでもローカル変数が持つ値は
変わらないと思っていたのですが。

補足日時:2012/08/25 03:56
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!