クラス変数とインスタンス変数の違いについて調べて下記で学びました。
http://qiita.com/wat-aro/items/f37d7b1a2e341d06966e
http://qiita.com/mogulla3/items/cd4d6e188c34c6819709
ですが、いまいち使いどころというか、どのように使い分けするのがより無駄なく機能的なのかがイメージつかなく、どちらでもたいして労力変わらず同じものを呼びだせてしまう理解から抜け出せません。
それぞれの使いどころの具体的な説明をいただけましたら幸いです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
クラス変数とインスタンス変数は性質が全く異なるモノです。実例を見ながら、動作を説明しましょう。
ちょっとしたTODOツールを作ろうと思いました。全体はまだですが、とりあえずTodo
クラスを作って、テキストメッセージや終わったかどうかを管理しようと思います。
Ruby
1class Todo 2 def initialize(text) 3 @text = text 4 @done = false 5 end 6 7 def text 8 @text 9 end 10 11 def do! 12 if !@done 13 @done = true 14 end 15 end 16 17 def done? 18 @done 19 end 20end 21 22# 二つのTODOを作成 23todo1 = Todo.new('質問する。') 24todo2 = Todo.new('ベストアンサーを選ぶ。') 25 26# 一つ目はもう実行した 27todo1.do! 28 29# 一つ目について終わっているのか? 30if todo1.done? 31 puts "TODO「#{todo1.text}」は終わりました。" 32else 33 puts "TODO「#{todo1.text}」はまだやってません。" 34end 35 36# 二つ目について終わっているのか? 37if todo2.done? 38 puts "TODO「#{todo2.text}」は終わりました。" 39else 40 puts "TODO「#{todo2.text}」はまだやってません。" 41end
出力結果
TODO「質問する。」は終わりました。 TODO「ベストアンサーを選ぶ。」はまだやってません。
二つのTODOは独立しています。なので、一つ目だけ終わらせても、二つ目は終わってません。さて、もし、インスタンス変数@done
がクラス変数@@done
だったらどうなるのでしょうか?
Ruby
1class Todo 2 def initialize(text) 3 @text = text 4 @@done = false 5 end 6 7 def text 8 @text 9 end 10 11 def do! 12 if !@@done 13 @@done = true 14 end 15 end 16 17 def done? 18 @@done 19 end 20end 21 22# 二つのTODOを作成 23todo1 = Todo.new('質問する。') 24todo2 = Todo.new('ベストアンサーを選ぶ。') 25 26# 一つ目はもう実行した 27todo1.do! 28 29# 一つ目について終わっているのか? 30if todo1.done? 31 puts "TODO「#{todo1.text}」は終わりました。" 32else 33 puts "TODO「#{todo1.text}」はまだやってません。" 34end 35 36# 二つ目について終わっているのか? 37if todo2.done? 38 puts "TODO「#{todo2.text}」は終わりました。" 39else 40 puts "TODO「#{todo2.text}」はまだやってません。" 41end
出力結果
TODO「質問する。」は終わりました。 TODO「ベストアンサーを選ぶ。」は終わりました。
あれ、一つ目しか終わってないのに、二つ目も終わってしまいました。なぜそうなるのか、一番目のコードと何が違うのかを見ましょう。
一番目のコードでは、todo1
は終わったかどうかを管理するために@done
を持っています。そして、todo2
も終わったかどうかを管理するために@done
を持っています。@done
はインスタンス変数なので、この二つは別のモノです。つまり、お互いに独立しており、片方を変えても、もう片方には一切影響はありません。
しかし、クラス変数にすると事情が変わります。二番目のコードでは、todo1
は@@done
を持ち、todo2
は@@done
を持っています。ここまでは同じように見えますが、この二つの@@done
はクラス変数なので同じモノです。先ほどとは全く逆で、お互いは同じモノを示しており、片方を変えれば、もう片方も変わっています。
こうして、二番目のコードでは、todo1
だけ終わらせたつもりが、todo2
まで終わっていたという、使えないコードになってしまいました。
では、クラス変数はどういうときに使うのでしょうか?Todoの数や終わった数をカウントして、完了率を出そうと思います。正常に動く一番目のコードを次のように拡張してみました。
Ruby
1class Todo 2 def initialize(text) 3 @text = text 4 @done = false 5 @total_todo_count ||= 0 6 @total_todo_count += 1 7 @done_todo_count ||= 0 8 end 9 10 def text 11 @text 12 end 13 14 def do! 15 if !@done 16 @done = true 17 @done_todo_count += 1 18 end 19 end 20 21 def done? 22 @done 23 end 24 25 def done_persent 26 100 * @done_todo_count / @total_todo_count 27 end 28end 29 30# 二つのTODOを作成 31todo1 = Todo.new('質問する。') 32todo2 = Todo.new('ベストアンサーを選ぶ。') 33 34# 一つ目はもう実行した 35todo1.do! 36 37# 一つ目について終わっているのか? 38if todo1.done? 39 puts "TODO「#{todo1.text}」は終わりました。" 40else 41 puts "TODO「#{todo1.text}」はまだやってません。" 42end 43puts "TODOの完了率は#{todo1.done_persent}%です。" 44 45# 二つ目について終わっているのか? 46if todo2.done? 47 puts "TODO「#{todo2.text}」は終わりました。" 48else 49 puts "TODO「#{todo2.text}」はまだやってません。" 50end 51puts "TODOの完了率は#{todo2.done_persent}%です。"
出力結果
TODO「質問する。」は終わりました。 TODOの完了率は100%です。 TODO「ベストアンサーを選ぶ。」はまだやってません。 TODOの完了率は0%です。
あれ、TODOは二つあって、一つしか終わってないから、完了率は50%になるはずですよね?何が悪かったのでしょうか。とりあえず、新しく追加した@done_todo_count
と@total_todo_count
をクラス変数に変えてみましょう。
Ruby
1class Todo 2 def initialize(text) 3 @text = text 4 @done = false 5 @@total_todo_count ||= 0 6 @@total_todo_count += 1 7 @@done_todo_count ||= 0 8 end 9 10 def text 11 @text 12 end 13 14 def do! 15 if !@done 16 @done = true 17 @@done_todo_count += 1 18 end 19 end 20 21 def done? 22 @done 23 end 24 25 def done_persent 26 100 * @@done_todo_count / @@total_todo_count 27 end 28end 29 30# 二つのTODOを作成 31todo1 = Todo.new('質問する。') 32todo2 = Todo.new('ベストアンサーを選ぶ。') 33 34# 一つ目はもう実行した 35todo1.do! 36 37# 一つ目について終わっているのか? 38if todo1.done? 39 puts "TODO「#{todo1.text}」は終わりました。" 40else 41 puts "TODO「#{todo1.text}」はまだやってません。" 42end 43puts "TODOの完了率は#{todo1.done_persent}%です。" 44 45# 二つ目について終わっているのか? 46if todo2.done? 47 puts "TODO「#{todo2.text}」は終わりました。" 48else 49 puts "TODO「#{todo2.text}」はまだやってません。" 50end 51puts "TODOの完了率は#{todo2.done_persent}%です。"
出力結果
TODO「質問する。」は終わりました。 TODOの完了率は50%です。 TODO「ベストアンサーを選ぶ。」はまだやってません。 TODOの完了率は50%です。
今度はちゃんと50%になりました。なぜ、うまくいったのでしょうか?
三番目のコードでは@total_todo_count
と@done_todo_count
はインスタンス変数でした。ですので、todo1
とtodo2
それぞれが持っている@total_todo_count
と@done_todo_count
は独立しています。todo1
が終わったからとカウントを追加してもtodo1
の中のカウントしか増えません。そもそも、最初の全体数@total_todo_count
も独立しているので、互いにずっと1
のままです。
そこでクラス変数の出番です。クラス変数@@total_todo_count
と@@done_todo_count
とすることで、todo1
とtodo2
から共通で使えるようになりました。@@total_todo_count
は最初のinitialize
で正常にカウントされ、2
になります。その後、todo1
が終わりましたので、@@done_todo_count
は1
になります。これはtodo1
がみている@@total_todo_count
と@@done_todo_count
、todo2
がみている@@total_todo_count
と@@done_todo_count
、両方がそうなっています。なぜなら、それらは同じモノであり、@@total_todo_count
と@@done_todo_count
は、todo1
とtodo2
が共通で使っているからです。
といことで、クラス変数とインスタンス変数は全く異なる性質のモノですので、使い分けどころか、どちらを使うという選択はできません。インスタンス変数をクラス変数に、クラス変数をインスタンス変数に変えれば、おかしな動きになってしまいます。
そうそう、Rubyにはクラスのインスタンス変数というモノがありますが、それはまた異なった性質のモノです。コレまで話していた内容はクラス変数とインスタンス変数の違いであり、クラスのインスタンス変数は含まれていませんので、ご注意ください。もし、そちらをお聞きになりたいのであれば、質問を編集するなり,再度質問をするなりしてください。
投稿2016/07/16 12:54
総合スコア21735
0
Rubyに限らず一般的な話ですが、クラスは定義した型です。
インスタンスはクラスをもとに生成したオブジェクトです。
なので、クラス変数は、クラスに紐づいている変数
インスタンス変数は、インスタンスに紐づいている変数です。
例えば、「人間」というクラスがあったとして、あなたや私は「人間」クラスのインスタンスです。
※人間という型をもとに作られたそれぞれのオブジェクト(生きている人)です。
人間のクラス変数として考えられるのは、例えば目の数とか人間全体の人数とかです。
目の数はあなたも私も普通2つですよね、なので情報として一つ持てばいいので普通はクラスに1か所だけ持ちます。(定数でいいとかいうのはおいておいて)
人間のインスタンス変数として考えられるのは、人間ごとに違うもの、
例えば身長や体重などです。(人間それぞれで違う情報)
これは、どのようなクラスでも同じ、例えば車クラスのインスタンスは、レクサスとかキューブとか
そんな感じで、型全体で共有するのはクラス変数、インスタンスそれぞれで持つものはインスタンス変数として使用します。
投稿2016/07/16 07:30
総合スコア2208
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
基本的に、Rubyにおいてクラス変数は(よほどそれを必要とする理由がない限り)使うべきでないと考えます。クラス変数は、クラス自体・インスタンス間で共有されるので、思わぬところで変更が入って、デバッグしにくくなる原因となります。
クラスメソッドで使う値などは、クラスインスタンス変数(クラス内での単なるインスタンス変数)を使えば充分に書けます。そして、それはクラスメソッド外からはうっかり書き換えられないので、スコープ的にも適切な場合が多いです。
投稿2016/07/16 05:39
総合スコア145183
0
参考:
- インスタンス変数とクラス変数の違い http://uxmilk.jp/24330
...
インスタンス変数とクラス変数の最も大きな違いは、インスタンス毎に値が固有であるか否かにあります。
...
-インスタンス変数とクラスインスタンス変数の違い http://blog.livedoor.jp/sasata299/archives/51676591.html
...
インスタンス変数はオブジェクトに属しているので、オブジェクト毎に値を持ちます。
...
クラスインスタンス変数はクラスに属しているのでクラスに対して一つだけ値を持ちます。
...
- クラス変数とインスタンス変数の違い https://teratail.com/questions/21092
投稿2016/07/16 05:38
総合スコア22324
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/16 08:59
2016/07/16 14:32
2016/07/21 14:43
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/07/21 14:44