コンテンツにスキップ

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`が関連しているのはこのためです。