Ruby self — 我是誰?我在哪?

Andrew
3 min readDec 8, 2020

--

self 是什麼?

之前提到類別方法時,我們就已經看過 self

class Army
def fight # 實體方法
puts "我要打倒天龍人!"
end

def self.inspire # 類別方法
puts "全部的人都起身戰鬥!"
end
end

self 是一種 Ruby 的虛擬變數(pseudo-variable),先來看看它屬於哪一類

self.class
=> Object

好!確定身分了!self 是個物件!

不過這個物件有點特別,self 會永遠指向當前正在執行的物件。(喔?似乎和 JavaScript 的 this 有點類似?)

在類別裡,self 代表目前的類別:

class Treasure
def self.self # 類別方法
self
end
end
Treasure.self
=> Treasure

在實體裡,self 則代表目前的實體:

def self
self
end
captain = "魯夫"captain.self
=> "魯夫"

什麼都沒有直接用 self 會是什麼?

想知道的話我們用 who_am_i 這個方法來看:

def who_am_i
self
end
who_am_i
=> main

印出了 main !這個 main 是什麼呢?別小看它,它是 Ruby 裡層級頗高的一個物件,它也是直接隸屬於 Object 這個類別下的實體。
(原來跟 self 是同事啊!)

main 的存在非常有趣,之前提過在物件導向的概念裡,呼叫方法會需要 receiver,而 Ruby 之所以能直接呼叫方法,是因為在這個環境裡,其實已經先偷偷做好了一顆物件,因此如果沒有指定任何物件,這顆物件就會指向 main

self 可以用來區分方法和變數

在 Ruby 裡

class Pirate
def supernew
"最惡世代"
end

def difference
supernew = "超新星"
puts supernew # 印出變數
puts self.supernew # 印出實體方法
end
end
Pirate.new.difference

在 Ruby 裡,同時存在同名的變數和方法時,會以變數優先,但若真的需要呼叫方法,而需要忽略變數的話,可以使用 self 來達成。

也可以把 self 當作回傳值使用

肚子有點餓了,想吃個點心:

class Snack
attr_accessor :bowl

def initialize
@bowl = []
end

# 把穀片倒入碗裡
def add_cereal
@bowl << :cereal
self
end

# 把牛奶倒入碗裡
def add_milk
@bowl << :milk
self
end

# ... 其他點心
end

現在來盛一碗享用吧!

my_snack = Snack.new.add_cereal.add_milk

來看看碗裡有什麼:

my_snack.bowl# 印出
[:cereal, :milk]

嗯~太棒了!是我喜歡的穀片 + 牛奶~開動!(嚼嚼嚼)

今天就先到這邊啦~真的嘴饞打算去吃個點心
而且關於自己的事也不好講太多(菸)

如果想了解更多 Ruby 的 self ,網路上有更多大大們分享的精彩文章,都非常值得一看喔!

--

--