スポンサーリンク
コンストラクタとインスタンスメソッド
Rubyのクラスの特徴
- メンバ変数は、@変数名で定義する(特に宣言する必要ない)
- メンバ変数は全てprivate
- initializeメソッドが、コンストラクタのこと
- コンストラクタの呼び方は、クラス名.new(引数)
- コンストラクタに引数を渡す際は( )を省略することはできない
1 2 3 4 5 6 7 | class Person def initialize name @name = name end end person = Person.new("alice") |
コンストラクタも普通のメソッド同様、引数のデフォルト値を設定できる。デフォルト値の無い引数があれば、コンストラクタ(.new)を呼ぶ際には必ず引数として渡さないといけない。
メンバ変数は特に宣言する必要はなく、@変数名の形で書くだけ。全てのメンバ変数はprivate扱いになるので、外のクラスから触りたい場合は、それぞれの変数に対するアクセサメソッド(ゲッター、セッター)を定義する必要がある。
アクセサメソッド名の名付けの慣習
- ゲッターのメソッド名は、変数名そのまま
- セッターのメソッド名は、変数名=
例えば、
メンバ変数nameのゲッターメソッド名をname
メンバ変数nameのセッターメソッド名をname=
と定義すると、
1 2 | person.name = "bob" puts person.name |
っていう風な直感的な書き方ができる(直接変数を触っているように見えるが、そうじゃない)。
「=」はメソッド名の一部だが、なぜかこの場合、間にスペースを空けても問題ない。普通はメソッド名の途中にスペースを入れるのはNG。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class Person def initialize name @name = name end def name @name end def name= name @name = name end end person = Person.new("alice") puts person.name #=> alice person.name = "bob" puts person.name #=> bob |
スポンサーリンク
アクセサメソッド
Rubyにはアクセサメソッドを簡単に定義する方法が備わっている。
1 | attr_accessor :変数名 |
こうするだけ。
これだけで変数名の定義と、その変数に対するゲッター、セッターの定義が完了する。
以下は上記のクラス定義と全く同じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Person def initialize name @name = name end attr_accessor :name end person = Person.new("alice") puts person.name #=> alice person.name = "bob" puts person.name #=> bob |
これだけでも十分すごいのに、なんと複数のメンバ変数(及びアクセサメソッド)を一気に作ることができる。その場合、「,」で区切って変数名にコロンを付けてを書くだけ。
1 2 3 4 5 6 7 8 | class Person def initialize name @name = name end attr_accessor :name, :age, :address end |
たったこれだけで、3つのメンバ変数(name, age, address)の宣言と、アクセサメソッドの設置が完了する。Javaでやっていたことは何だったのか。
セッターのみ、ゲッターのみ定義したい場合は、それぞれ以下のようにする。
ゲッターのみ↓
1 | attr_reader :変数名 |
セッターのみ↓
1 | attr_writer :変数名 |
以下のように、それぞれ定義していない方を使おうとするとエラーになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Person def initialize name @name = name end attr_reader :age attr_writer :address end person = Person.new("alice") #person.age = 20 #error p person.age #=>nil person.address = "東京" #puts person.address #error |
クラスメソッドの定義と呼び方
クラスメソッドとは、Javaで言うstaticメソッド。
クラスメソッドを定義する時は、selfを使う。クラス定義スコープ内ではselfはそのクラス自身を指す(インスタンスではないので注意)。
1 2 3 4 5 6 7 8 9 | class Person def self.class_method puts "Personクラスのクラスメソッドが呼ばれました" end end Person.class_method #=> Personクラスのクラスメソッドが呼ばれました |
selfを使ってそのクラス自身を指すやり方ではなく、そのままクラス名を使っても良い。
1 2 3 | def Person.class_method puts "Personクラスのクラスメソッドが呼ばれました" end |
このやり方なら、クラス定義スコープの外部ででもクラスメソッドを定義できるらしいが、どういう時にそんな変なことするのか個人的にはよく分からない。
複数のクラスメソッドを定義したい場合なんかは、こんな書き方も出来る。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Person class << self def hoge puts "クラスメソッドhogeが呼ばれた" end def fuga puts "クラスメソッドfugaが呼ばれた" end end end Person.hoge #=> クラスメソッドhogeが呼ばれた Person.fuga #=> クラスメソッドfugaが呼ばれた |
クラス変数
クラス変数には@@を付ける。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Person @@person_num = 0 def initialize @@person_num = @@person_num + 1 end def self.person_num @@person_num end end puts Person.person_num #=> 0 Person.new puts Person.person_num #=> 1 Person.new puts Person.person_num #=> 2 |
privateメソッド
Rubyでは普通にメソッドを定義するとpublic扱いになり、クラス外から呼ぶことができる。
privateメソッドを定義するには、private以下にメソッドを定義する。
1 2 3 4 5 6 7 8 9 10 | class Hoge def foo bar end private def bar puts "bar" end end |
privateメソッドの約束事
- privateメソッドを呼ぶ際は、レシーバを指定できない。
- レシーバは暗黙的に、selfになっており、それが自クラスのclassオブジェクト or サブクラスのclassオブジェクトである必要がある。
結果的に、privateメソッドは、自クラスorサブクラスの定義域内でしか呼べない。