new、initialize、そしてallocate¶
クラスのインスタンスを作成するには、そのクラスに対して`new`を呼び出します。
person = Person.new
ここで、`person`は`Person`のインスタンスです。
`person`ではあまり多くのことはできません。そこで、いくつかの概念を追加してみましょう。`Person`には名前と年齢があります。「すべてはオブジェクト」のセクションで、オブジェクトは型を持ち、いくつかのメソッドに応答すると述べました。これはオブジェクトと対話する唯一の方法なので、`name`と`age`の両方のメソッドが必要になります。この情報は、常にアットマーク(`@`)が付いたインスタンス変数に格納します。また、`Person`が私たちの選んだ名前と年齢0で存在するようにしたいと考えています。「存在するようになる」部分は、特別な`initialize`メソッドでコーディングします。これは通常、*コンストラクタ*と呼ばれます。
class Person
def initialize(name : String)
@name = name
@age = 0
end
def name
@name
end
def age
@age
end
end
これで、次のように人を作成できます。
john = Person.new "John"
peter = Person.new "Peter"
john.name # => "John"
john.age # => 0
peter.name # => "Peter"
(`name`が`String`であることを指定する必要があるのに、`age`には指定する必要がない理由がわからない場合は、グローバル型推論アルゴリズムを確認してください)
`new`で`Person`を作成しますが、初期化は`new`メソッドではなく`initialize`メソッドで定義しました。なぜでしょうか?
答えは、`initialize`メソッドを定義したときに、Crystalが次のように`new`メソッドを定義したためです。
class Person
def self.new(name : String)
instance = Person.allocate
instance.initialize(name)
instance
end
end
まず、`self.new`という表記に注目してください。これは、クラスの特定のインスタンスではなく、**クラス** `Person`に属するクラスメソッドです。そのため、`Person.new`を実行できます。
次に、`allocate`は、指定された型の初期化されていないオブジェクトを作成する低レベルのクラスメソッドです。基本的には、オブジェクトに必要なメモリを割り当て、その上で`initialize`が呼び出され、最後にインスタンスが返されます。安全ではないため、通常は`allocate`を呼び出しませんが、`new`と`initialize`が関連しているのはこのためです。