次のプログラムは、実行するとエラーが発生します。正しく動作するようにプログラムを修正してください。
class Robot
def self.ping
@@count += 1
end
def count
@@count
end
end
r1 = Robot.new
r1.ping
r2 = Robot.new
r2.ping
r1.ping
puts Robot.count
なお、Robot
クラスの本来の仕様は次の通りです:
- インスタンスメソッド
ping
を呼ぶとクラスの共有カウンタが1ずつ増加する。
- クラスメソッド
count
を呼ぶと現在のカウンタの値が返される。
したがって、このプログラムを端末上で実行すると、画面に3という数が表示されることになります。
--
黒田努
解答と解説の表示・非表示
解答と解説
今回はトリッキーなところはまったくありません。実際にRubyインタープリタで実行しながら修正していけば、比較的短時間で正解にたどり着くと思います。
しかし、この問題を紙と鉛筆だけで解けと言われたらどうでしょうか。
かなり正答率は低くなると思われます。
解答を送っていただいた方からも、「勉強になった」というコメントが届きました。
***
クラス変数とクラスメソッドについて簡単におさらいしておきましょう。
クラス変数は、名前の前に記号 @@
を付けて表記します。それを定義したクラス、そのサブクラス、そのインスタンスで共有される変数です。それら以外のオブジェクトからは参照できません。
クラスメソッドは、クラスが提供する「便利な関数(機能)」です。インスタンスメソッドがインスタンスの状態を参照したり、変更したりするのとは対照的です。クラスメソッドは、クラスの外部からでも利用できます。
***
さて、すぐに気づくのは、クラスメソッドとインスタンスメソッドの定義が逆になっている点ですね。クラスメソッド名の前には self.
を付けますが、インスタンスメソッド名には付けません。
class Robot
def ping
@@count += 1
end
def self.count
@@count
end
end
しかし、2カ所のメソッド定義を修正するだけでは不十分です。実行してみると次のようなエラーメッセージが出ます。
robot.rb:3:in `ping': uninitialized class variable @@count in Robot (NameError)
クラス変数 @@count
が定義されていません。
クラス変数の初期化はどこで行うべきでしょうか。
次のコードは、ペンネーム y@su さんによる Robot
クラスの定義です。
class Robot
def initialize
@@count ||= 0
end
def ping
@@count += 1
end
def self.count
@@count
end
end
これでも動くのですが、コンストラクタである initialize
メソッドの役割は、Robot
インスタンスを初期化することです。クラス変数を初期化する場所としてはあまり適切ではありません。
クラス変数はクラス定義の中で初期化します。
では、模範解答です。
class Robot
@@count = 0
def ping
@@count += 1
end
def self.count
@@count
end
end
r1 = Robot.new
r1.ping
r2 = Robot.new
r2.ping
r1.ping
puts Robot.count
大詰めさん、MTGさん、river125さんのコードは、模範解答とまったく同じでした。ありがとうございました。