前言

Symbol 符號在Ruby裡,常見以冒號配文字的形式出現 (譬如是 :user or :title)。

乍看之下,不就是 冒號 + 變數 或是 冒號 + 字串 嗎?

就是因為外表上蠻相似的,因此容易與”變數”及”字串”混淆。對新手而言,搞懂symbol及正確的使用符號是有難度的。

在這裡我就嘗試說明在Ruby 世界裡的符號(Symbol)是什麼?它跟字串又有何不同? 首先我們先了解在Ruby的世界裡每一個變數、文字、數字都是物件,而symbol也是如此。

symbol1

“Symbol 其實是有點玄的東西,有些人認為它就是的變數,或就是只是個名字,但事實上它不就是變數或名字這麼簡單,你可以想像它是一個「帶有名字的物件」”- 五倍紅寶石學院 -

Symbol VS 字串 VS 變數

換句話說,數字5也是物件(數字物件),文字”hello”(字串物件),而符號 :name則是(符號物件)。 從另一個角度來看,把”符號”看作值(value)就會容易理解許多。

symbol1

舉例來說,我們會把“變數”=“值”( age = 29),但是不會把”值”指定給”值”(13=25),因為這是很明顯的錯誤。所以符號不能指定給值(:age=29)因為符號就是屬於值。


2.6.3 :007 > :age = 29
Traceback (most recent call last):
SyntaxError((irb):7: syntax error, unexpected '=', expecting end-of-input)
symbol1

字串也是如此,當理解(29 = “Rex”)是錯誤的時候,就不難看出(:name = “Rex”)也是錯誤的了。

Symbol 效能 ??


2.6.3 :001 > "rex".object_id
 => 70167057786220
2.6.3 :002 > "rex".object_id
 => 70167057770160
2.6.3 :003 > "rex".object_id
 => 70167069560160
2.6.3 :004 >

從上面的程式碼看出,每一次呼叫 “rex” 字串都會跟 Ruby 要一個新的 object id,也就是說都不會存在同一個記憶體裡。


2.6.3 :004 > :rex.object_id
 => 1509788
2.6.3 :005 > :rex.object_id
 => 1509788
2.6.3 :006 > :rex.object_id
 => 1509788
2.6.3 :007 >

然而只要是一樣的symbol,就會有相同的 object id。例如:上面的程式碼可看出 :rex 符號都是擁有相同的 object_id => 1509788

Symbol有相同的object_id,表示他們是同一顆東西,當 Ruby 需要重複存取符號時,就不需要重新產生新的記憶體,效能上也會相對的好一些。

另一個不同之處,就是字串的內容可以修改,但是符號不行。我們可以用存取陣列的方式修改字串,但是符號是無法經由任何方法改變的。因為即使是一個字元的改變(打錯字)就會變成是不同的符號了。


2.6.3 :001 > name = "Kevin"
 => "Kevin"
2.6.3 :002 > name[1] = "C"
 => "C"
2.6.3 :003 > puts name
KCvin

在這裡我們把陣列裡 index=1的字 ‘e’ 更換為 ‘C’,這樣是沒問題的! 但是符號的話會是什麼情況呢?


2.6.3 :004 > :name = "Kevin"
Traceback (most recent call last):
        3: from /Users/kevin/.rvm/rubies/ruby-2.6.3/bin/irb:23:in 
        2: from /Users/kevin/.rvm/rubies/ruby-2.6.3/bin/irb:23:in `load'
        1: from /Users/kevin/.rvm/rubies/ruby-2.6.3/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in 
SyntaxError ((irb):4: syntax error, unexpected '=', expecting end-of-input)
:name = "Kevin"

跟之前的例子一樣,符號是值,所以不可以把值 “Kevin” 字串指定給另一個值