例如:
hash[:name]
对比。
hash['name']
TL;DR:
使用符号不仅在比较时节省时间,还因为它们只存储一次而节省内存。
Ruby Symbols是不可变的(不能被改变),这使得查找某些内容更加容易。
简短回答:
使用符号不仅在比较时节省时间,还因为它们只存储一次而节省内存。
Ruby中的符号基本上是"不可变字符串",这意味着它们不能被改变,并且意味着当在源代码中多次引用相同的符号时,始终将其存储为相同的实体,例如具有相同的对象ID。
a = 'name'
a.object_id
=> 557720
b = 'name'
=> 557740
'name'.object_id
=> 1373460
'name'.object_id
=> 1373480 # !! different entity from the one above
# Ruby assumes any string can change at any point in time,
# therefore treating it as a separate entity
# versus:
:name.object_id
=> 71068
:name.object_id
=> 71068
# the symbol :name is a references to the same unique entity
相反的,字符串是可变的,它们可以随时更改。这意味着Ruby需要在其单独的实体中存储源代码中提到的每个字符串,例如,如果您在源代码中多次提到一个字符串“name”,Ruby需要将它们全部存储在单独的String对象中,因为它们可能会在以后更改(这是Ruby字符串的本质)。
如果您将字符串用作哈希键,则Ruby需要评估字符串并查看其内容(并计算哈希函数),并将结果与已存储在哈希表中的键的(哈希)值进行比较。
如果您将符号用作哈希键,则它的固有属性是不可变的,因此Ruby基本上只需比较(哈希函数的)对象ID与已存储在哈希表中的键的(已哈希的)对象ID即可。(速度更快)
缺点: 每个符号都占用Ruby解释器符号表中的一个插槽,而这些插槽永远不会被释放。 符号永远不会被垃圾回收。 因此,当您拥有大量符号(例如自动生成的符号)时,就存在一个特殊情况,您应该评估这如何影响Ruby解释器的大小(例如,如果您以编程方式生成太多符号,则Ruby可能会耗尽内存并崩溃)。
注:
如果您进行字符串比较,Ruby可以通过比较它们的对象ID来比较符号,而无需评估它们。这比比较字符串要快得多,因为字符串需要被评估。
如果您访问哈希表,Ruby总是会应用哈希函数来计算出一个"哈希键",无论您使用什么键。您可以想象一下类似于MD5哈希的东西。然后,Ruby将这些"哈希键"相互比较。s = "foo"
h = {}
h[s] = "bar"
s.upcase!
h.rehash # must be called whenever a key changes!
h[s] # => nil, not "bar"
h.keys
h.keys.first.upcase! # => TypeError: can't modify frozen string
仅对于字符串键,Ruby将使用冻结副本而不是对象本身。
2)程序中所有:bar
的出现都只存储一次字母“b”、“a”和“r”。在Ruby 2.2之前,不断创建从未重用过的新Symbols
是一个坏主意,因为它们将永远留在全局Symbol查找表中。Ruby 2.2会进行垃圾回收,所以不用担心。
3)实际上,在Ruby 1.8.x中计算Symbol的哈希值不需要任何时间,因为直接使用对象ID:
:bar.object_id == :bar.hash # => true in Ruby 1.8.7
Symbols
)会随着会话的变化而发生改变::bar.hash # => some number that will be different next time Ruby 1.9 is ran
回复:为什么使用符号的优势比字符串更好?
(非常)稍微快一点的值查找,因为哈希一个符号相当于哈希一个整数,而不是哈希一个字符串。
缺点:消耗程序符号表中永远不会释放的一个槽位。
我对Ruby 2.x中引入的冻结字符串非常感兴趣,希望能有后续报道。
当你处理来自文本输入的大量字符串时(例如通过Rack传递的HTTP参数或负载),在任何地方使用字符串都更容易。
当你处理数十个从不改变的字符串时(如果它们是你的业务“词汇”),我认为将它们冻结可能会有所不同。我还没有进行任何基准测试,但我猜它的性能接近符号。