Rubyにおけるinitializeについて知ろう

Rubyを学習していると避けて通れないinitializeメソッド。
「え？initializeメソッドってオブジェクトを作る時に初期化するためのメソッドでしょ？簡単じゃん」と思う方もいるかもしれません。
ですが、わかっているようでわかっていないという事があるので（私がそうでした。。。）、
この記事を読んでinitializeメソッドについて少し詳しくなりましょう！

# initializeメソッドとは何か？
簡潔にまとまると、
「インスタンス化する際、インスタンス変数（プロパティ）に初期値を設定する」
です。
「いや、それが理解できたら苦労しないよ」
という声も聞こえてきそうなので、これから具体例を出し説明します。

# initializeメソッドは勝手に呼び出される？！
initializeメソッドはインスタンス化の際に勝手に呼び出されます。そしてprivateメソッドです。（ここではprivateメソッドについては詳しく説明しません。クラスの外からは呼び出せないメソッドと考えてください。）
つまりインスタンス化を行ったことがある人ならば、知らずしらずinitializeメソッドを使っています。
例えば以下のコードがあったとします。
```ruby
class Test
  def message
    puts 'メソッドが呼ばれました！'
  end
end
```
通常メソッドを呼び出す場合、以下のように呼び出す必要があります。
```ruby
Test.new.message  # -> メソッドが呼ばれました！
```
ところが、messageの部分をinitializeに変えてみると、
```ruby
class Test
  def initialize
    puts 'メソッドが呼ばれました！'
  end
end
```
メソッドを指定しなくてもinitializeメソッドが呼び出されます！
```ruby
Test.new  # -> メソッドが呼ばれました！
```
反対にメソッドを指定するとエラーが返ってきます。これはinitializeメソッドがprivateメソッドだからです。
```ruby
Test.new.initialize  # -> private method `initialize' called for 〜
```
これでinitializeメソッドがインスタンス化の際に勝手に呼び出され、privateメソッドであることがわかりました。

# initializeメソッドの役割
改めて、initializeメソッドの役割は「インスタンス化する際、インスタンス変数（プロパティ）の初期値を設定する」でした。
例えばあなたが、ゲームを作ろうと思った時、おそらくキャラクタークラスを作成して、そのクラスからcharacter1、character2、、、といったオブジェクトを作るはずです。
character1もcharacter2もそれぞれ固有の名前を持ち、攻撃力や防御力があると仮定しましょう。
インスタンス化をするとしたら以下のようなコードになりそうです。
```ruby
character1 = Character.new('名前','攻撃力','防御力')
```
上記を踏まえクラスを作成しようと考えると、引数を受け取る必要がありそうですね。
この引数を受け取る場所がinitializeメソッドです。
initializeメソッドは勝手に呼び出されましたよね？
なので、インスタンス化するだけで自動で引数を受け取って処理してくれます。
```ruby
class Character
  def initialize(name, attack, defence)
    puts "名前:#{name}"
    puts "攻撃力:#{attack}"
    puts "防御力:#{defence}"
  end
end

character1 = Character.new('ピカチュウ', 100, 60)
# 以下、出力結果
# 名前：ピカチュウ
# 攻撃力：100
# 防御力：60
```

ちなみに、以下のようにインスタンスメソッドでも同じ結果を出力できます。
```ruby
class Character
  def create_character(name, attack, defence)
    puts "名前:#{name}"
    puts "攻撃力:#{attack}"
    puts "防御力:#{defence}"
  end
end

character1 = Character.new.create_character('ピカチュウ', 100, 60)
# 以下、出力結果
# 名前：ピカチュウ
# 攻撃力：100
# 防御力：60
```
「え？じゃあやっぱりinitializeメソッドっていらなくない？」
と思われるかもしれませんが、実は後者はバグを引き起こす可能性を孕んでいます。
それぞれオブジェクトを確認してみるとわかります。
### initializeメソッドを使った場合
```ruby
character1 = Character.new('ピカチュウ', 100, 60)
p character1  # -> #<Character:0x000000010807ba58>
```
ちゃんとオブジェクトが返ってきています。
### インスタンスメソッドを使った場合
```ruby
character1 = Character.new.create_character('ピカチュウ', 100, 60)
p character1  # -> nil
```
ん？nil？
そうです。上記の方法だとオブジェクトは返ってきません。
自分自身を返すことを明示的に示さなければなりません。
```ruby
class Character
  def create_character(name, attack, defence)
    puts "名前:#{name}"
    puts "攻撃力:#{attack}"
    puts "防御力:#{defence}"
    self
  end
end

character1 = Character.new.create_character('ピカチュウ', 100, 60)
p character1  # -> #<Character:0x00000001077cae18>
# 以下、出力結果
# 名前：ピカチュウ
# 攻撃力：100
# 防御力：60
```
このように、initializeメソッドを使わずともプロパティを設定することは可能ですが、ひと手間かかってしまい、そのひと手間を忘れるとバグの温床になってしまいます。
なので、インスタンス化と同時に初期値を設定しておきたいクラスについては、initializeメソッドを明示的にしておくほうが無難です。

# initializeメソッドの引数
initializeメソッドの挙動を見てきましたが、他にもinitializeメソッドには特徴があります。
それは「initializeメソッドに引数をつけると、オブジェクトを作成する際、同じ数の引数を渡さなければいけない。」ということです。
つまり受け取る初期値の数を予め指定できるのです。
実際に見てみましょう。
```ruby
class Character
  def initialize(name, attack, defence)
    @name = name
    @attack = attack
    @defence = defence
  end

  def showStatus
    puts "名前:#{@name}"
    puts "攻撃力:#{@attack}"
    puts "防御力:#{@defence}"
  end
end

character1 = Character.new  #ここではオブジェクトを作成
###################
#色々処理を書いて
###################
# ここでキャラクターのステータスを出したい
character1.showStatus
# 以下、出力結果
# `initialize': wrong number of arguments (given 0, expected 3) (ArgumentError)
```
直訳すると「initializeは3つの引数を期待しているが、0個の引数が渡されている」となります。
ではちゃんと引数を渡してあげましょう。
```ruby
class Character
  def initialize(name, attack, defence)
    @name = name
    @attack = attack
    @defence = defence
  end

  def showStatus
    puts "名前:#{@name}"
    puts "攻撃力:#{@attack}"
    puts "防御力:#{@defence}"
  end
end

character1 = Character.new('ピカチュウ', 100, 60)  #ここでちゃんと引数を渡す
###################
#色々処理を書いて
###################
# ここでキャラクターのステータスを出したい
character1.showStatus
# 以下、出力結果
# 名前：ピカチュウ
# 攻撃力：100
# 防御力：60
```
無事に出力されました！
このようにinitializeメソッドは、引数を指定することで、オブジェクトを作成する時に初期値を渡すように指定することができます。

# まとめ
いかがでしたでしょうか？
initializeメソッドについて少しは知ることが出来ましたでしょうか？
以上から、独自のプロパティを持つオブジェクトを作るならinitializeメソッドを活用するほうが良いということがわかりました。
逆に言えば、独自のプロパティを持たない場合はわざわざ明示的に書く必要はなさそうですね。
とても浅い内容でしたが、この記事を見てくださった方のinitializeメソッドの理解の一助となれれば幸いです。