コンテンツにスキップ

メソッドとインスタンス変数

コンストラクタの引数にインスタンス変数を指定する短縮記法を使うと、インスタンス変数への代入をより簡潔に書くことができます。

class Person
  def initialize(@name : String)
    @age = 0
  end

  def age
    @age
  end
end

今のところ、名前をつけて Person のインスタンスを生成することくらいしかできません。age は常に0のままです。それでは、person が年齢を重ねることができるようにしてみましょう。

class Person
  def initialize(@name : String)
    @age = 0
  end

  def age
    @age
  end

  def become_older
    @age += 1
  end
end

john = Person.new "John"
peter = Person.new "Peter"

john.age # => 0

john.become_older
john.age # => 1

peter.age # => 0

メソッド名の先頭は小文字である必要があります。また、メソッド名には使うのは小文字とアンダースコア、そして数値のみとすることが慣習的です。

ゲッターとセッター

Crystal の標準ライブラリ にはゲッターとセッターを完結に定義するためのマクロがいくつかあります。

class Person
  property age
  getter name : String

  def initialize(@name)
    @age = 0
  end
end

john = Person.new "John"
john.age = 32
john.age # => 32

ゲッターとセッターのマクロの詳細は、標準ライブラリのObject#getter, Object#setterObject#propertyの辺りを参照してください。

少し捕捉をすると、上記のように become_older メソッドを元々の Person クラスのなか で定義するだけではなく、元々のクラスと別で改めて定義することも可能です。Crystal はそれらのすべての定義を1つのクラスにまとめます。つまり、以下の場合でも問題なく動作します。

class Person
  def initialize(@name : String)
    @age = 0
  end
end

class Person
  def become_older
    @age += 1
  end
end

メソッドの再定義とprevious_def

もしあるメソッドが再度定義された場合、最後に定義されたものが優先されます。

class Person
  def become_older
    @age += 1
  end
end

class Person
  def become_older
    @age += 2
  end
end

person = Person.new "John"
person.become_older
person.age # => 2

そのときprevious_defを使って以前に定義されたメソッドを呼び出すことが可能です。

class Person
  def become_older
    @age += 1
  end
end

class Person
  def become_older
    previous_def
    @age += 2
  end
end

person = Person.new "John"
person.become_older
person.age # => 3

引数の括弧もない場合、previous_def には呼び出し元のメソッドと同じ引数がそのまま渡されます。そうでない場合には、指定した引数が渡されます。

キャッチオール初期化

インスタンス変数は initialize メソッドの外部で初期化することもできます。

class Person
  @age = 0

  def initialize(@name : String)
  end
end

このとき @age はどのコンストラクタでも0で初期化されます。これは重複を避けることができるだけでなく、クラスを再オープンしてインスタンス変数を追加する際にNil型になることを防ぐことにも役立ちます。