为什么符号不是冻结的字符串?

Ale*_*fee 23 ruby symbols

我理解字符串和符号之间的理论差异.我理解符号用于表示概念或名称或标识符或标签或键,而字符串是一个字符包.我知道字符串是可变的和瞬态的,其中符号是不可变的和永久的.我甚至喜欢的符号怎么在我的文本编辑器不同的字符串.

困扰我的是,实际上,Symbols与Strings非常相似,因为它们没有被实现为Strings,这会引起很多麻烦.它们甚至不支持鸭子打字或隐式强制,不像其他着名的"相同但不同"的夫妻,Float和Fixnum.

当然,最大的问题是从其他地方进入Ruby的哈希,比如JSON和HTTP CGI,使用字符串键而不是符号键,因此Ruby程序必须向后弯曲才能在前面或在查找时进行转换.仅仅存在HashWithIndifferentAccess于Rails和其他框架中,以及它在Rails和其他框架中的广泛使用,都表明这里存在一个问题,需要抓一点痒.

谁能告诉我为什么Symbols不应该被冻结的实际原因?除了"因为它总是如何完成"(历史)或"因为符号不是字符串"(乞求问题).

考虑以下令人惊讶的行为:

:apple == "apple"  #=> false, should be true

:apple.hash == "apple".hash #=> false, should be true

{apples: 10}["apples"]  #=> nil, should be 10

{"apples" => 10}[:apples]  #=> nil, should be 10

:apple.object_id == "apple".object_id #=> false, but that's actually fine
Run Code Online (Sandbox Code Playgroud)

只需要让下一代Rubyists不那么困惑就是:

class Symbol < String
  def initialize *args
    super
    self.freeze
  end
Run Code Online (Sandbox Code Playgroud)

(还有很多其他的库级黑客攻击,但仍然不太复杂)

也可以看看:

更新:我认为Matz在class Symbol < String这里做得很好:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/9192(感谢Azolo挖掘它,以及还有马茨的"最终收回".

Azo*_*olo 8

这个答案与我原来的答案截然不同,但我在Ruby邮件列表上遇到了几个有趣的 线程.(两个好读)

因此,在2006年的某个时刻,matz将该Symbol课程实施为Symbol < String.然后Symbol剥离了班级以消除任何可变性.所以a Symbol实际上是不可改变的String.

然而,它被还原了.给出理由是

即使它高度反对DuckTyping,人们倾向于在类上使用case,而Symbol <String通常会导致严重的问题.

所以你的问题的答案仍然是:a Symbol就像a String,但事实并非如此.
问题不在于Symbol不应该String,而是在历史上不是.


Emi*_*ily 5

我不知道一个完整的答案,但这里有很大一部分:

符号用于散列键的原因之一是给定符号的每个实例都是完全相同的对象.这意味着:apple.id将始终返回相同的值,即使您没有传递它.另一方面,"apple".id每次都会返回一个不同的id,因为创建了一个新的字符串对象.

这种差异是为什么符号被推荐用于散列键.使用符号时,不需要进行对象等效性测试.它可以直接与对象身份短路.