符號 <> 看!又是一塊歷史正文!讀懂這些,通往 ONEPIECE 的路就不遠了!

[Day16] 但是歷史正文上的符號真是複雜難懂啊…

哈囉各位晚安,今天要介紹的是**符號(Symbol)**!

大家對符號應該不陌生,畢竟每天傳訊息都會用到啊!
????????????????????? 啊不是這是表情符號…


符號是什麼?

在 Ruby 裡,符號是一種「帶有名字的物件」。
會用冒號 : 開頭來表示符號,同時符號也具有唯一性(immutable),一旦被建立後就無法改變。

最容易看到符號的地方就是在雜湊(Hash)了!我們經常使用符號來表示雜湊裡的鍵(key):

1
2
3
4
5
hash = {
:cat => 1,
:dog => 2,
:man => 3
}

也可以寫成這樣:

1
2
3
4
5
hash = {
cat: 1,
dog: 2,
man: 3
}

另外,符號也可以拿來指稱方法:

1
2
3
4
def call_me
puts "打電話給我!"
end
=> :call_me

符號跟變數有什麼不同?

首先,雖然看起來和變數超級像,但符號它不是「變數」而是「值」。

如果我們把符號當作變數一樣在用:

1
2
3
4
5
6
7
8
9
10
11
# 把字串指定給符號
:name = 1

=> SyntaxError ((irb):15: syntax error, unexpected '=', expecting end-of-input)
:name = 1

# 把字串指定給符號
:name = "Hi"

=> SyntaxError ((irb):16: syntax error, unexpected '=', expecting `end')
:name = "Hi"

Ruby 會告訴你這樣的語法是錯誤的!因為按照正常的程式邏輯,我們不能把一個值指定給另一個值。


一個特定符號只有一個 Object_id

任何一個符號都有著自己的記憶體位置,並始終指向那個位置,因此會較省記憶體。比起字串,用符號來當作雜湊的鍵(key),存取效能的表現會更好。

為什麼存取效能更好?原因是當程式在比較兩個物件時,若是符號,程式會直接比對 object_id 是否相同。然而在比對字串時,則是會從第一個字元開始,逐一比對是否相同。因此,在效能上字串的時間複雜度會隨著字元數量增加而提升,但符號就沒有這樣的問題。

接著我們來看看字串和符號的差別:

1
2
3
4
5
6
7
8
9
10
11
12
13
"hi".object_id
=> 180
"hi".object_id
=> 200
"hi".object_id
=> 220
"hi".object_id
=> 240

:call_me.object_id
=> 2034908
:call_me.object_id
=> 2034908

然而,符號用太多而沒有歸還記憶體時,會出現 記憶體流失(Memory leak) 的問題(簡單來說,是一種在設計上造成的記憶體浪費)


其他像是數字或 truefalsenil 的 object_id 也會變動嗎?

數字的 object_id 是固定的,被放在記憶體的奇數位置上。譬如數字 n ,位置就是 2n+1:

1
2
3
4
5
6
7
8
9
10
1.object_id
=> 3
2.object_id
=> 5
3.object_id
=> 7
5.object_id
=> 11
8.object_id
=> 17

truefalsenil 則是在記憶體的偶數位置,也是固定的:

1
2
3
4
5
6
true.object_id
=> 20
false.object_id
=> 0
nil.object_id
=> 8

關於 Ruby 的符號今天就介紹到這邊啦!希望之有時間的話能再提一些自己在實際運用上的案例及理解,謝謝大家的觀看!