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
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
4条答案
按热度按时间wb1gzix01#
Ruby符号是不可变的(不能被改变),这使得查找更容易
如果你使用一个字符串作为哈希键,Ruby需要评估这个字符串,查看它的内容(并计算一个哈希函数),然后将结果与已经存储在哈希中的键的(哈希)值进行比较。
如果你使用一个符号作为哈希键,这就意味着它是不可变的,所以Ruby基本上只需要将object-id(的哈希函数)与已经存储在哈希中的键的(哈希的)object-id进行比较(快得多)。
如果你做字符串比较,Ruby可以通过比较符号的对象id来比较符号,而不需要对它们求值,这比比较字符串要快得多,因为字符串需要求值。
如果你访问一个散列,Ruby总是应用一个散列函数,从你使用的任何键计算一个"散列键",你可以想象类似MD5散列的东西,然后Ruby将这些"散列键"相互比较。
每次在代码中使用字符串时,都会创建一个新示例-创建字符串比引用符号慢。
从Ruby 2.1开始,当你使用冻结字符串时,Ruby会使用相同的string对象,这避免了必须创建相同字符串的新副本,并且它们被存储在一个垃圾收集的空间中。
https://web.archive.org/web/20180709094450/http://www.reactive.io/tips/2009/01/11/the-difference-between-ruby-symbols-and-strings
http://www.randomhacks.net.s3-website-us-east-1.amazonaws.com/2007/01/20/13-ways-of-looking-at-a-ruby-symbol/
https://www.rubyguides.com/2016/01/ruby-mutability/
thtygnil2#
原因是效率,在一个字符串上有多个增益:
1.符号是不可变的,所以不需要问“如果键改变会发生什么?”
1.字符串在代码中是重复的,通常会占用更多的内存空间。
1.散列查找必须计算键的散列来比较它们。对于字符串,这是
O(n)
,对于符号,这是常量。此外,Ruby 1.9引入了一个简化的语法,只用于符号键的哈希(例如
h.merge(foo: 42, bar: 6)
),Ruby 2.0有keyword arguments,只用于符号键。1)您可能会惊讶地发现Ruby对待
String
键的方式与对待其他类型的键的方式不同。仅对于字符串键,Ruby将使用冻结副本而不是对象本身。
2)在一个程序中,对于所有
:bar
的出现,字母“B”、“a”和“r”只存储一次。在Ruby 2.2之前,不断创建新的Symbols
是一个坏主意,因为它们将永远保留在全局符号查找表中。Ruby 2.2将垃圾收集它们,所以不用担心。3)实际上,在Ruby 1.8.x中,计算Symbol的哈希值并不需要花费任何时间,因为对象ID是直接使用的:
在Ruby 1.9.x中,随着哈希值从一个会话到另一个会话的变化(包括
Symbols
的哈希值),这一点也发生了变化:332nm8kg3#
回复:使用字符串有什么好处?
nfg76nw04#
我对Ruby 2.x中引入的冻结字符串非常感兴趣。
当您处理来自文本输入的大量字符串时(例如,我考虑的是HTTP参数或有效负载,通过Rack),在任何地方使用字符串都要容易得多。
当你处理几十个符号,但它们从来没有改变过(如果它们是你的业务“词汇”),我想冻结它们可以带来不同。我还没有做任何基准测试,但我猜它会接近符号的性能。