還記得前天,我們在說雜湊(Hash)的時候,有提到**雜湊的鍵(key)可以用字串(string)或符號(symbol)**來表示,例如:
hash1 = { "name" => "Annie", "age" => 25 }
hash2 = { :name => "Ruby", :age => 21 }
hash2也可以改寫成 = { name: "Ruby", age: 21 }
那篇文章一直強調 "string" 與 :symbol 是不一樣的,那到底哪裡不一樣呢?其實有位厲害的鐵人賽選手在那篇文章下的留言回答了!講得非常清楚噢!快去看快去看,然後我今天的文章就打完了(大誤)XD
從文章留言以及Ruby中文官方網站中,我們可以得到以下結論:
「到底什麼時候使用symbol、什麼時候使用string呢?」
由於相同名字的symbol在記憶體裡都占同一個位置,也就是指向同一個物件,所以適用於識別物件,就像是身分證字號一樣,是獨一無二的,永遠不會改變。而每一個字串(就算名字一樣),在記憶體中都是不同位置,適用於可改變的內容,例如綽號、電話...等,就不適合拿來作為識別用途。
總而言之(丸尾上身):
如果是物件的識別(例如hash中的key),用symbol。
如果是物件的內容(例如hash中的value),用string。
好的,我們還是來看一看書中對於符號的說明(p.74):
『Ruby解譯器的典型石作品會維護一份符號表(symbol table),把解譯器已經知道的類別、方法和變數之名稱全都存放在此表中。』
路過的阿嬤問:『阿這嘸蝦咪好康呢?』
『這讓解譯器得以避免大部份的字串比較工作,例如:解譯器在指稱方法名稱時可透過其在符號表中的位置。這將代價較高的字串運算轉換成了代價較低的整數運算。』
路過的阿嬤問:『工蝦啦?』
我想這段的意思,就是指symbol的效能會比string好,因為symbol表中所有東西都有固定的位置,找得比較快,而字串還得去找他在哪,效能就會比較低了。
另外符號的寫法也不是只有:symbol而已噢!看看以下:
:symbol
:"symbol"
:'symbol'
第二和第三行並不是新的寫法,這三行到irb中執行都會得到相同的結果:
=> :symbol
只是有加上引號只是方便於俱有空格的符號:
:"Hello Kitty"
=> :"Hello Kitty"
:Hello Kitty
SyntaxError # 要有空格就一定要加上引號才行,不然會噴錯!
如同字串有 %q 與 %Q 、陣列有 %w 與 %W ,symbol也有一個 %s (沒有%S)的語法,例如:
%s[Hello]
=> :Hello
%s[Hello Kitty]
=> :"Hello Kitty"
接下來書中提到symbol常被用在一個很特別的情境下,例如:**如果我們要查某個物件是不是有支援 .each 這個方法?**我們可以這麼做:
[].respond_to? :each
=> true # 陣列有.each這方法
{}.respond_to? :each
=> true # 雜湊也有.each這方法
"".respond_to? :each
=> false # 字串就沒有.each這方法
"".respond_to? :succ
=> true # 不過字串有昨天提到的.succ這方法
總之是個很好的檢測方式,書中就給了個例子:
name = :size
if xxx.respond_to? name
xxx.send(name)
end
上面這例子是會測試某物(xxx)是否會回應所指定的方法(.size),如果答案是true,就調用該方法!書中指出這種能夠觀察並修改行為的程式碼稱作「反射程式碼(reflective code)」。
最後最後,我們來看字串與符號的轉換:
(還記得以前學過 .to_s 、 .to_i 、 .to_a )
符號改成字串一樣可以使用 .to_s
:Ruby.to_s
=> "Ruby"
也可以用 .id2name 達到同樣的效果
:Ruby.id2name
=> "Ruby"
而字串改符號的話,要使用 .to_sym 或 .intern
"Ruby".to_sym
=> :Ruby
"Ruby".intern
=> :Ruby
路過的阿嬤:『安捏喔!賀啦~哇瞭蓋啊~』
=================================================
第13天~對不起其實根本沒有路過的阿嬤XD
Always remember that the future comes one day at a time. - Dean Acheson
未來,是一天一天的來!