跳至主要内容

[Ruby] Symbol

可以把 Symbol 想像是一個「帶有名字的物件」。因為下面的一些特性,讓 Symbol 在 Ruby 中主要用作 hash 的鍵(key)或者是用來指稱方法的名稱。

  • immutable: 被建立後就不能改變。
  • 任何 symbol 都指稱到同一個記憶體位置,因此較省記憶體。
  • 以 Symbol 當作鍵(key)的效能會比字串當作鍵的效能來得好。

建立 Hash

# Symbol 都是以冒號(:)開頭

# Hash Rocket
new_hash = {
:one => 1,
:two => 2,
:three => 3
}

# 把冒號放在 symbol 的後面,並可省略 '=>'
# 不能寫 "one : 1",sybmol 後面要直接接':',不能先接空格
new_hash = {
one: 1,
two: 2,
three: 3
}

Symbol 跟變數有什麼不同?

變數是一個指向某個物件的名字,例如:

greeting = "Hello Ruby"

上面這行語法,是指 greeting 這個名字指向 "Hello Ruby" 這個字串物件,但如果沒有 "Hello Ruby" 這個字串給它指,這個名字本身是沒辦法單獨存在的。

而 Symbol 是一個「帶有名字的物件」,本身不需要指向任何東西也可以拿來用。而且你也沒辦法直接拿 Symbol 來當變數,像這樣會出現語法錯誤:

:name = "Aaron Chen"   # 這得到 SyntaxError 的錯誤訊息

Symbol 跟字串有什麼不同?

Symbol 指稱的到的相同記憶體位置

相同"樣子"的字串實際上都是在不同記憶體位置的不同物件,但是相同"樣子"的 Symbol 指稱到的是記憶體中的相同物件:

5.times do
puts "hello".object_id # 會得到 5 個不同的 id (表示是在 5 個不同記憶體位置的不同物件)
end

5.times do
puts :hello.object_id # 只會是同一個 id(直接從記憶體拿,不用重新產生)
end

Symbol 的效能比字串好

也因此因此 Symbol 的效能比字串要好一些,因為 Symbol 在做比較的時候,是直接比對這兩顆物件的 object id 是不是相同,而字串比較則是一個字母一個字母逐一比對。所以在效能上來說,字串在做比較的時間複雜度會隨著字母的數量(N)而增加,但 Symbol 的比較因為只比較是不是同一顆物件,所以它的複雜度是固定的。

因為 Symbol 不可變(immutable)的特性,以及它的查找、比較的速度比字串還快,它很適合用來當 Hash 的 Key。

字串的內容可以變,但 Symbol 不行

p :symbol       # :symbol
p "symbol" # "symbol"

p :symbol[2] # m
p "symbol"[2] # m

:symbol[2] = "k" # return ERROR
"symbol"[2] = "k"

字串跟 Symbol 是可以互相轉換的

# 字串轉成 Symbol
"name".to_sym
"name".intern
%s(name)


# Symbol 轉成字串
:name.to_s

參考資料