更新日:
【Ruby】 attr_readerメソッドの使い方を基礎から学んで整理しよう
attr_readerとは、インスタンス変数の読み取り専用のメソッド(ゲッターメソッド)を自動で定義することが出来るメソッドのことです。
Rubyではクラスのインスタンス変数を外部から参照する場合は、以下のように読み取り専用メソッドを定義する必要があります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class User
def initialize(name, age)
@name = name
@age = age
end
def name # 読み取り専用のメソッド
@name
end
def age # 読み取り専用のメソッド
@age
end
end
tanaka = User.new('田中太郎', 18)
p tanaka.name # @nameを読み取る
#=> "田中太郎"
p tanaka.age # @ageを読み取る
#=> 18
上記のコードだと参照したいインスタンス変数が増えるたびに読み取り専用のメソッドを定義する必要があるので、コード量が増えて可読性が下がります。
しかし、以下のコードのようにattr_readerメソッドを使えば、わざわざ明示的に読み取り専用のメソッドを定義する必要がないのでコード量も少なく済みます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User
attr_reader :name, :age # これで読み取り専用のメソッドが定義される
def initialize(name, age)
@name = name
@age = age
end
end
tanaka = User.new('田中太郎', 18)
p tanaka.name # @nameを読み取る
#=> "田中太郎"
p tanaka.age # @ageを読み取る
#=> 18
このように、attr_readerメソッドに参照したいインスタンス変数名を指定するだけで、そのインスタンス変数の読み取り専用のメソッドを定義することが出来ます。
attr_readerメソッドの使い方
attr_readerメソッドが何をしているのか良く分からないという方は、getter/setter(ゲッター/セッター)を理解してないことが原因の1つとしてあります。
この章では、attr_readerメソッドの使い方だけではなく、大きく関係するgetter(ゲッター)も一緒に解説するので、attr_readerメソッドの必要性や使用場面を具体的に理解することが出来ます。
基本構文
attr_readerメソッドは、以下のように文字列かシンボルで読み取りたいインスタンス変数名を指定します。
1
2
3
4
5
# シンボルの場合
attr_reader :インスタンス変数名
# 文字列の場合
attr_reader 'インスタンス変数名'
インスタンス変数名は、以下のように@なしで記述します。
1
2
3
4
5
# シンボルの場合
attr_reader :name
# 文字列の場合
attr_reader 'name'
上記の記述によって自動で定義される読み取りメソッドは、以下の通りです。(詳細は後述します。)
1
2
3
def name
@name
end
また、複数指定する場合は以下のようにカンマで区切ります。
1
2
3
4
5
# シンボルの場合
attr_reader :name, :age
# 文字列の場合
attr_reader 'name', 'age'
ゲッターメソッドの必要性
クラスで定義したインスタンス変数をクラスの外部からアクセスするには、インスタンスメソッドで経由させる必要があります。
例えば、以下のtanaka.say
はsayインスタンスメソッドを経由しているので、クラス外部からでも@nameと@ageを参照することが出来ています。
1
2
3
4
5
6
7
8
9
10
11
12
13
class User
def initialize(name, age)
@name = name
@age = age
end
def say
p "#{@name}、#{@age}歳です。"
end
end
tanaka = User.new('田中太郎', 18)
tanaka.say #=> "田中太郎、18歳です。"
しかし、以下のコードのようにインスタンスメソッドを経由せずに直接tanaka.@name
で参照しようとするとエラーが発生します。
1
2
3
4
5
6
7
8
9
10
class User
def initialize(name, age)
@name = name
@age = age
end
end
tanaka = User.new('田中太郎', 18)
tanaka.@name
#=> syntax error, unexpected tIVAR, expecting '(' tanaka.@name
クラスの外部からインスタンス変数を参照する場合には、インスタンスメソッドを経由して参照する必要があります。
ゲッターメソッドとは?
インスタンス変数の読み取り専用のインスタンスメソッドを「ゲッターメソッド」と呼びます。ゲッターメソッドは、以下のnameメソッドやageメソッドのように、メソッドが呼び出された時に各インスタンス変数を返すように定義します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class User
def initialize(name, age)
@name = name
@age = age
end
def name # ゲッターメソッド
@name # メソッドが呼び出されたら@nameを返す
end
def age # ゲッターメソッド
@age # メソッドが呼び出されたら@ageを返す
end
end
tanaka = User.new('田中太郎', 18)
p tanaka.name # nameメソッドを呼び出す
#=> "田中太郎"
p tanaka.age # ageメソッドを呼び出す
#=> 18
上記のtanaka.name
のように、name
というゲッターメソッド(読み取り専用のインスタンスメソッド)を経由することでインスタンス変数(@name)をクラスの外部から参照することが出来ています。
attr_readerメソッドの役割とは?
ゲッターメソッドでクラス外部からインスタンス変数を参照することが出来ましたが、参照したいインスタンス変数が増える度にゲッターメソッドを定義しなければなりません。
例えば、@nameや@age以外にも@mailや@cellにアクセスしたい場合は、以下のコードのようにゲッターメソッドを定義するので、コードがどんどん増えて可読性が下がります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class User
def initialize(name, age, mail, cell)
@name = name
@age = age
@mail = mail
@cell = cell
end
def name # ゲッターメソッド
@name
end
def age # ゲッターメソッド
@age
end
def mail # 新たに追加したゲッターメソッド
@mail
end
def cell # 新たに追加したゲッターメソッド
@cell
end
end
しかし、attr_readerメソッド
を使えば、明示的に1つ1つのゲッターメソッドを定義する必要もなく以下の記述だけで済みます。
1
2
3
4
5
6
7
8
9
10
11
class User
# この記述だけで各ゲッターメソッドが定義される
attr_reader :name, :age, :mail, :cell
def initialize(name, age, mail, cell)
@name = name
@age = age
@mail = mail
@cell = cell
end
end
attr_readerを使った場合でも、以下のように各インスタンス変数の参照をすることが出来ています。
1
2
3
4
5
tanaka = User.new('田中太郎', 18, 'hoge@example.com', '070-09xx-xxxx')
p tanaka.name
#=> "田中太郎"
p tanaka.age
#=> 18
これはattr_reader :name
と記述すると、以下のコードのように@nameを参照するためのゲッターメソッドが定義されるためです。
1
2
3
4
5
6
attr_reader :name
# 以下のメソッドは、上記の記述で自動で定義されるメソッド
def name
@name
end
このように、attr_readerメソッドはゲッターメソッドを定義することが出来ます。
他のアクセサメソッドとの違い
インスタンス変数の読み取り(参照)専用メソッドの「ゲッターメソッド」の他にも、インスタンス変数の書き込み(変更)専用メソッドである「セッターメソッド」があります。
以下のようにセッターメソッドを定義すると、クラス外部からインスタンス変数の値を変更することが出来ます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class User
attr_reader :age
def initialize(name, age)
@name = name
@age = age
end
def age=(age) # セッターメソッド
@age = age # メソッドが呼び出されたら@ageを渡された値に変更
end
end
tanaka = User.new('田中太郎', 18)
p tanaka.age
#=> 18
tanaka.age = 33 # age=メソッドを呼び出す
p tanaka.age
#=> 33 # 変更されている
上記では、セッターメソッドを定義した事でインスタンス変数の変更を行うことが出来ました。
しかし、以下のコードのようにゲッターメソッドを定義するattr_readerメソッドを記述のみでは、インスタンス変数を参照するだけでセッターメソッドのような値を変更する機能はないので注意してください。
1
2
3
4
5
6
7
8
9
10
11
12
class User
attr_reader :name, :age
def initialize(name, age)
@name = name
@age = age
end
end
tanaka = User.new('田中太郎', 18)
tanaka.age = 33 # インスタンス変数に値を変更しようとする
# => undefined method `age=' for #<User:0x00007fdcec921a78 @name="田中太郎", @age=18> (NoMethodError)
このようにインスタンス変数の値を変更する場合は、セッターメソッドかセッターメソッドを定義するattr_writerメソッドが必要になります。詳細は「attr_writerメソッドの使い方」を参考にしてください。
attr_readerメソッドの使い所
attr_readerメソッドは、ゲッターメソッドを定義するので「インスタンス変数を参照するだけ」で変更することは出来ません。その為、クラスの外部からはインスタンス変数の参照のみで変更は加えたくない場合に良く使われます。
例えば、ユーザーの名前や年齢は参照や変更することが出来るが、メールアドレスは参照のみで変更されたくない場合は以下のように記述します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User
attr_reader :name, :age, :mail
attr_writer :name, :age # @name,@ageの値を変更できるようにする
def initialize(name, age, mail)
@name = name
@age = age
@mail = mail
end
end
tanaka = User.new('田中太郎', 18, 'hoge@example.com')
tanaka.age = 33
tanaka.mail = 'fuga@example.com'
# => undefined method `mail=' for #<User:0x00007fd49f054670> (NoMethodError)
上記のコードは、attr_writerメソッドによって@nameや@ageの値は変更可能にしていますが、@mailは含まれないので参照のみになります。
attr系メソッドまとめ
アクセサメソッドを定義してくれるメソッドは、attr_readerメソッドの他にもattr_writerメソッド、attr_accessorメソッドがあります。各メソッドの特徴は、以下の表の通りです。
attr系メソッド | 定義されるメソッド | インスタンス変数の値に対して |
---|---|---|
attr_reader | ゲッターメソッドを定義 | 参照のみ |
attr_writer | セッターメソッドを定義 | 変更のみ |
attr_accessor | ゲッター/セッター両方を定義 | 参照と変更の両方 |
ゲッターメソッドとセッターメソッドの両方を定義し、インスタンス変数の値を参照と変更の両方可能にするのがattr_accessorメソッドです。よく使われるメソッドなので、まだ知らないという方は「attr_accessorメソッドの使い方」を参考にしてください。
この記事のまとめ
- attr_readerメソッドは、ゲッターメソッドを定義してくれるメソッド
- ゲッターメソッドとは、インスタンス変数の値を参照するためのメソッド
- attr_readerメソッドは、インスタンス変数の値の参照のみで変更を加えることは出来ない