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

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

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

当然,最大的问题是从其他地方进入Ruby的哈希,比如JSON和HTTP CGI,使用字符串键而不是符号键,因此Ruby程序必须向后弯曲才能在前面或在查找时进行转换。 HashWithIndifferentAccess存在,以及它在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 

只需要让下一代Rubyists不那么困惑就可以了:

 class Symbol < String def initialize *args super self.freeze end 

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

也可以看看:

  • http://onestepback.org/index.cgi/Tech/Ruby/SymbolsAreNotImmutableStrings.red
  • http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol
  • 为什么我的代码在使用哈希符号而不是哈希字符串时会中断?
  • 为什么在Ruby中使用符号作为哈希键?
  • 什么是符号,我们如何使用它们?
  • Ruby符号与哈希中的字符串
  • 无法在Ruby中获得符号的悬念
  • http://blog.arkency.com/could-we-drop-symbols-from-ruby/
  • Ruby符号是否存在,因为字符串是可变的而不是实体的?

更新:我认为Matz在这里很好地为class Symbol < String了案例: http ://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/9192(感谢Azolo挖掘这一点,以及Matz’最终的撤回)。

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

因此,在2006年的某个时刻,matz将Symbol类实现为Symbol < String 。 然后剥离Symbol类以消除任何可变性。 所以Symbol实际上是一个不可变的String

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

即使它高度反对DuckTyping,人们倾向于在类上使用case,而Symbol

所以你的问题的答案仍然是: 一个Symbol就像一个String ,但它不是。
问题不在于Symbol不应该是String ,而是在历史上不是。

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

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

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

另一个考虑是"apple".each_char是有道理的,但是:apple.each_char没有。 字符串是“有序的字符列表”,但符号是没有显式值的primefaces数据点。

我会说HashWithIndifferentAccess实际上certificate了Ruby符号正在履行两个不同的角色; 符号 (基本上类似于其他语言中的枚举)和实习字符串 (实质上是抢先优化,补偿了解释ruby的事实,因此没有智能优化编译器的好处。)

请参阅此答案: https : //stackoverflow.com/a/6745253/324978

主要原因:性能(符号存储为整数,永远不会被垃圾收集)和一致性( :admin:admin将始终指向同一个对象,其中"admin""admin"没有该保证),等等。

它的基础是,这些不应该是真的:

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

符号始终是相同的对象,而文本则不是。

如果一个String可以inheritanceSymbol,因为它增加了很多function(变异)。 但是,Symbol永远不能用作“字符串”,因为在所有需要变异的情况下,它都会失败。

无论如何,正如我上面所说,string == symbol必须永远不会返回true,如上所述。 如果您对此有所了解,您会注意到在考虑子类实例的类中没有合理的==实现。