Ruby中冒號開頭Symbol與&:to_s用法解釋

本篇介紹Ruby中特有的寫法,將解答&:to_s:symbol這兩種寫法的意義。並依序介紹以下議題:

Symbol和String的不同之處

分別宣告兩個symbol與string。

1
2
3
4
5
6
7
8
[22] pry(main)> sym = :abc
=> :abc
[23] pry(main)> str = "abc"
=> "abc"
[24] pry(main)> sym2 = :abc
=> :abc
[25] pry(main)> str2 = "abc"
=> "abc"

用object_id來看看是否為同一個物件。從下面結果可以發現,在參照同樣的symbol:abc時,不同的變數參考的是同一個物件。而String參考的物件是不同的。

1
2
3
4
5
6
7
8
9
[26] pry(main)> sym.object_id
=> 1172168
[28] pry(main)> sym2.object_id
=> 1172168
[29] pry(main)> str.object_id
=> 70232488314360
[30] pry(main)> str2.object_id
=> 70232505015640
[31] pry(main)>

all_symbols 與 include? 搭配運用

在終端機輸入Symbol.all_symbols可以列出目前所有的Symbol。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[34] pry(main)> Symbol.all_symbols
=> [:freeze,
:inspect,
:intern,
:object_id,
:const_missing,
:method_missing,
:method_added,
:singleton_method_added,
:method_removed,
:singleton_method_removed,
:method_undefined,
:singleton_method_undefined,
:length,
:size,
:gets,
:succ,
:each,
:proc,
:lambda,
:send,
:__send__,
:__attached__,
:initialize,
.
.
.

我們把用all_symbols取出的陣列用變數symbols存起來。這樣我們就可以用include?來檢查某個symbol是否已經宣告。

1
2
3
4
5
6
7
[23] pry(main)> all_symbols.include?(:sym)
=> true
# :sym是系統預設的所以顯示true
[24] pry(main)> all_symbols.include?(:abc)
=> false
# :abc是我亂輸入的所以顯示false
[25] pry(main)>

&:to_s的用法與原理

以下兩個寫法效果相同,:代表一個Symbol,當Symbol遇上&符號時,會把to_s方法轉變為proc,而是否能轉變為proc則是看Class中有沒有to_proc方法,這是ruby中的duck typing特性所致。我會另外寫一篇來說明duck typing是如何運作。

1
2
3
4
[72] pry(main)> [1,2,3,4].map(&:to_s)
=> ["1", "2", "3", "4"]
[73] pry(main)> [1,2,3,4].map{|i| i.to_s}
=> ["1", "2", "3", "4"]

String、Symbol和Integer的互相轉換

Symbol可以轉換成String

1
2
[74] pry(main)> :a.to_s
=> "a"

String可以轉換成Symbol

1
2
[75] pry(main)> "a".to_sym
=> :a

Fixnum(數字的類別)不能轉換成Symbol,會出現錯誤。

1
2
3
[76] pry(main)> 1.to_sym
NoMethodError: undefined method `to_sym' for 1:Fixnum
from (pry):98:in `__pry__'

參考資料

誘人的ruby-符號篇

評論