attr_accessor <> 喲嚯嚯嚯~可以讓我看一下你的 code 嗎?

[Day22] 靈魂之王布魯克為您表演~ 45 度角!

學寫程式也有一陣子了,但直到最近才發現很多時候自己都只是知其然而不知其所以然,而沒有完全了解自己在寫的到底是什麼。

所以這篇就要來提一些很常被用到,但還不是非常清楚的東西:

什麼是 getter

顧名思義,就是「取得(某個東西)」的方法,在 Ruby 裡,我們會把取出實體變數這件事稱為 getter ,指的就是取出實體變數的方法。

1
2
3
4
5
6
7
8
9
10
class Cat
def initialize(name)
@name = name
end
end

miru = Cat.new('miru')

miru.name
=> NoMethodError (undefined method `name' for #<Cat:0x00007ff82783a578 @name="miru">)

在類別裡,沒有 getter 就無法取出實體變數的值。所以 miru 這個實體拿不到類別裡的實體變數 @name,如果要拿到 @name 的話,就必須給它一個 getter

1
2
3
4
5
6
7
8
9
10
11
12
13
class Cat
def initialize(name)
@name = name
end

def name #getter method
@name
end
end

miru = Cat.new('miru')
miru.name
=> "miru"

然而,如果每次要取實體變數的值都要重寫一次 getter ,嗯…用想的都覺得麻煩啊!因此超好用的 attr三兄弟 就誕生了!(登愣!)

指令 說明
attr_reader 用來取出實體變數。
attr_writer 用來指派實體變數。
attr_accessor 結合以上兩者,可取出也可指派實體變數。

讚嘆工程師們懶惰的美德!


attr_reader

attr_reader 可以幫助我們取出實體變數。

1
2
3
4
5
6
7
8
9
10
11
class Cat
attr_reader :name

def initialize(name)
@name = name
end
end

miru = Cat.new('miru')
miru.name
=> "miru"

跟剛剛完全一樣!改成用 attr_reader :name ,所以不用再寫:

1
2
3
def name
@name
end

一行抵三行,超級划算!


什麼是 setter

setter 也很好理解,就是「指派」的意思,在 Ruby 裡,我們會定義一個 setter 方法,透過呼叫這個方法,就可以重新指派實體變數。

attr_writer

我們延續剛剛的例子,如果今天有一隻叫做 miru 的貓

1
2
3
4
5
6
7
8
9
10
11
class Cat
attr_reader :name

def initialize(name)
@name = name
end
end

miru = Cat.new('miru')
miru.name
=> "miru"

而我想替祂換個更響亮的名字,結果不管怎麼寫通通都失敗了!

1
2
3
4
5
6
7
8
miru.name"neko"
=> ArgumentError (wrong number of arguments (given 1, expected 0))

miru.name."neko"
=> SyntaxError ((irb):14: syntax error, unexpected tSTRING_BEG)

miru.name = "neko"
=> NoMethodError (undefined method `name=' for #<Cat:0x00007fada005f780 @name="miru">

這是因為,在這個類別裡並沒有 setter ,因此產出的實體變數無法重新指派一個新的值。

那我們試試看加上 setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Cat
attr_reader :name

def initialize(name)
@name = name
end

def name=(name)
@name = name
end
end

miru = Cat.new('miru')
miru.name
=> "miru"

這時候就可以幫 miru 換個更好聽的名字了!

1
2
3
4
miru.name=("neko")
=> "neko"
miru.name
=> "neko"

而由於 Ruby 可以省略小括號的特性,以下這兩種 setter 的寫法可能更常見:

1
2
3
def name= name
@name = name
end
1
2
3
def name = name
@name = name
end

在使用上也可以:

1
2
miru.name = "puma"
=> "puma"

也因為這樣,才會説實體變數也是實體物件的屬性(attribute),這其中大部分的原因就是 setter 造成的!

當然,更懶惰的寫法就是用 attr_writer 啦!

1
2
3
4
5
6
7
8
9
10
11
12
class Cat
attr_reader :name
attr_writer :name

def initialize(name)
@name = name
end
end

miru = Cat.new('miru')
miru.name
=> "miru"

同樣也是一行抵三行啦!


attr_accessor

然而,沒有最懶,只有更懶。

attr_accessor 就是整合了前面兩者效果的神奇好夥伴,用了 attr_accessor 以後程式碼都變得超乾淨!等於一次擁有 attr_readerattr_writer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Cat
attr_accessor :name

def initialize(name)
@name = name
end
end

miru = Cat.new('miru')
miru.name
=> "miru"
miru.name = "wolf"
miru.name
=> "wolf"

是不是很心動!趕快打開 irb 玩玩看吧!

關於 attr_accessor ,大家可以拜讀龍哥這篇 Ruby 語法放大鏡之「attr_accessor 是幹嘛的?」,裡面有更多更專業的說明!


今天就介紹到這邊啦!大家明天見!