Symbol VS String
by Aaron • 10/22/2024, 5:21:42 PM

Ruby 常常看到在表示一個字串的時候有些地方用 Symbol, 有些地方卻用 String, 到底 Ruby 中的 Symbol 和 String 有什麼不同?什麼時候應該用 Symbol?
可變性
String 建立後是可以對某個字做更改的, 但是 Symbol 並不行
string = "string"
string[0] = "S"
# String
symbol = :symbol
symbol[0] = :S
# NoMethodError (undefined method `[]=' for :symbol:Symbol)
甚至我們細看這兩個所提供的 methods, 可以看到 Symbol 也沒有提供許多 BANG! methods 例如 downcase!, capitalize!
string.methods - symbol.methods
# [:unicode_normalize, :unicode_normalize!, :ascii_only?, :to_r, :unpack, :encode!, :unpack1, :%, :include?, :*, :+, :count, :partition, :+@, :-@, :<<, :to_c, :sum, :insert, :[]=, :bytesize, :succ!, :next!, :upto, :index, :rindex, :replace, :clear, :chr, :getbyte, :setbyte, :scrub!, :scrub, :undump, :byteslice, :dump, :downcase!, :hex, :capitalize!, :upcase!, :lines, :codepoints, :split, :swapcase!, :bytes, :oct, :prepend, :grapheme_clusters, :concat, :reverse, :reverse!, :to_str, :crypt, :ord, :strip, :to_i, :to_f, :center, :gsub, :ljust, :chars, :delete_suffix, :sub, :rstrip, :scan, :chomp, :rjust, :lstrip, :chop!, :delete_prefix, :chop, :sub!, :gsub!, :delete_prefix!, :chomp!, :strip!, :lstrip!, :rstrip!, :squeeze, :delete_suffix!, :tr, :tr_s, :delete, :each_line, :tr!, :tr_s!, :delete!, :squeeze!, :each_byte, :each_char, :each_codepoint, :each_grapheme_cluster, :b, :slice!, :rpartition, :force_encoding, :valid_encoding?, :unicode_normalized?, :encode]
儲存方式
相同 Symbol 只會有一個物件, String 每次建立都是新的物件
foo = "string"
foo.object_id
# 220
bar = "string"
bar.object_id
# 240
foo = :symbol
foo.object_id
# 902748
bar = :symbol
bar.object_id
# 902748
比較
相同的 Symbol 在記憶體會是同一個, 那當然相較 String 比較省記憶體, 那速度方面呢?
n = 100_000_000
results = Benchmark.bm(15) do |x|
x.report("symbol:") { n.times { :foo } }
x.report("string:") { n.times { "foo" } }
x.report("symbol compare:") { n.times { :foo == :foo } }
x.report("string compare:") { n.times { "foo" == "foo" } }
end
# user system total real
# symbol: 1.899853 0.003015 1.902868 ( 1.904602)
# string: 3.735612 0.006903 3.742515 ( 3.742530)
# symbol compare: 2.165240 0.004339 2.169579 ( 2.169611)
# string compare: 6.695739 0.017175 6.712914 ( 6.714193)
可以看到
- Symbol 建立速度較快,因為相同的 Symbol 只會被儲存一次。
- String 則每次建立都會分配新的記憶體,因此在頻繁創建字串時,String 會比較慢。
- Symbol 比較速度較快,因為它們只需比較 object_id(內部記憶體位置)。 String 則需要逐字比較內容,速度較慢。
總結
比較 | String | Symbol |
---|---|---|
可變性 | 可變 | 不可變 |
儲存方式 | 每次建立都是新的物件 | 相同 Symbol 只會有一個物件 |
用途 | 動態內容(如使用者輸入) | 固定識別符(如 Hash 鍵) |