すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Ruby

【Ruby】 attr_readerメソッドの使い方を基礎から学んで整理しよう

ぴっかちゃん
ぴっかちゃん

attr_readerとは、インスタンス変数の読み取り専用のメソッド(ゲッターメソッド)を自動で定義することが出来るメソッドのことです。

Rubyではクラスのインスタンス変数を外部から参照する場合は、以下のように読み取り専用メソッドを定義する必要があります。

user.rb | 読み取り専用のメソッドを定義する-->
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メソッドを使えば、わざわざ明示的に読み取り専用のメソッドを定義する必要がないのでコード量も少なく済みます。

user.rb | 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 'インスタンス変数名'

インスタンス変数名は、以下のように@なしで記述します。

attr_readerメソッドの使用例 -->
1
2
3
4
5
# シンボルの場合
attr_reader :name

# 文字列の場合
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を参照することが出来ています。

user.rb | 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で参照しようとするとエラーが発生します。

user.rb | インスタンスメソッドなしで直接@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メソッドのように、メソッドが呼び出された時に各インスタンス変数を返すように定義します。

user.rb | ゲッターメソッドを経由してインスタンス変数を参照する -->
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)をクラスの外部から参照することが出来ています。

ポイント
  1. インスタンス変数をクラスの外部からアクセスするには、インスタンスメソッドで経由させる必要がある
  2. インスタンス変数の読み取り専用のメソッドを「ゲッターメソッド」と呼ぶ

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つのゲッターメソッドを定義する必要もなく以下の記述だけで済みます。

user.rb | attr_readerを使った場合の記述量-->
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を使った場合でも、以下のように各インスタンス変数の参照をすることが出来ています。

user.rb | 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を参照するためのゲッターメソッドが定義されるためです。

attr_reader :nameを記述した場合-->
1
2
3
4
5
6
attr_reader :name

# 以下のメソッドは、上記の記述で自動で定義されるメソッド
def name
  @name
end

このように、attr_readerメソッドはゲッターメソッドを定義することが出来ます。

ポイント
  1. attr_readerメソッドを使えば、ゲッターメソッドを明示的に定義する必要がなくなる
  2. コード量が少なくなるので可読性が上がる
  3. attr_readerメソッドは、ゲッターメソッドを定義してくれるメソッド

他のアクセサメソッドとの違い

インスタンス変数の読み取り(参照)専用メソッドの「ゲッターメソッド」の他にも、インスタンス変数の書き込み(変更)専用メソッドである「セッターメソッド」があります。

以下のようにセッターメソッドを定義すると、クラス外部からインスタンス変数の値を変更することが出来ます。

user.rb | セッターメソッドの使用例-->
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メソッドを記述のみでは、インスタンス変数を参照するだけでセッターメソッドのような値を変更する機能はないので注意してください。

user.rb | セッターメソッドを定義しないでインスタンス変数に変更を加える場合-->
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メソッドは、ゲッターメソッドを定義するので「インスタンス変数を参照するだけ」で変更することは出来ません。その為、クラスの外部からはインスタンス変数の参照のみで変更は加えたくない場合に良く使われます。

例えば、ユーザーの名前や年齢は参照や変更することが出来るが、メールアドレスは参照のみで変更されたくない場合は以下のように記述します。

user.rb | @mailは参照のみで変更されたくない場合-->
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メソッドは、インスタンス変数の値の参照のみで変更を加えることは出来ない