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

Ruby 为什么符号不是冻结字符串?,ruby,symbols,Ruby,Symbols,我理解字符串和符号之间的理论区别。我理解符号是用来表示一个概念、一个名称、一个标识符、一个标签或一个键,而字符串是一袋字符。我知道字符串是可变的和瞬时的,其中符号是不变的和永久的。我甚至喜欢在我的文本编辑器中符号与字符串的不同 让我烦恼的是,实际上,符号与字符串非常相似,以至于它们没有作为字符串实现这一事实导致了很多麻烦。它们甚至不支持duck类型或隐式强制,不像其他著名的“相同但不同”的组合Float和Fixnum 当然,最大的问题是,从其他地方(如JSON和HTTP CGI)进入Ruby的哈

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

让我烦恼的是,实际上,符号与字符串非常相似,以至于它们没有作为字符串实现这一事实导致了很多麻烦。它们甚至不支持duck类型或隐式强制,不像其他著名的“相同但不同”的组合Float和Fixnum

当然,最大的问题是,从其他地方(如JSON和HTTP CGI)进入Ruby的哈希使用字符串键,而不是符号键,因此Ruby程序必须向后弯曲,以便在前面或在查找时转换这些值。仅仅是
hashwithindferencetaccess
的存在,以及它在Rails和其他框架中的大量使用,就说明了这里存在一个问题,一个需要解决的问题

有谁能告诉我为什么符号不应该是冻结字符串的实际原因吗?除了“因为它总是这样做”(历史)或“因为符号不是弦”(乞求问题)

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

: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
要想让下一代的红宝石爱好者不那么困惑,需要做的就是:

class Symbol < String
  def initialize *args
    super
    self.freeze
  end
类符号
(还有许多其他库级黑客,但仍然不太复杂)

另见:


更新:我认为Matz在这里很好地说明了
类符号
(感谢Azolo挖掘了这一点,也感谢Matz的最终撤回)。

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

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

这就是为什么建议哈希键使用符号的原因。使用符号时无需进行对象等效性测试。它可以直接短路到对象标识。

请参见以下答案:


主要原因:性能(符号存储为整数,从不进行垃圾收集)和一致性(
:admin
:admin
将始终指向同一个对象,其中
“admin”
“admin”
没有保证),等等。

这个答案与我的答案截然不同,但是我在Ruby邮件列表上遇到了一对夫妇。(两本书都读得很好)

因此,在2006年的某一时刻,matz将
Symbol
类实现为
Symbol
。然后剥离
Symbol
类以删除任何可变性。因此,
符号
实际上是一个不可变的
字符串

然而,它被恢复了。

尽管它非常反对DuckTyping,但人们倾向于使用case 在类上,符号<字符串通常会导致严重的问题

因此,您的问题的答案仍然是:
符号
类似于
字符串
,但事实并非如此。

问题不在于
符号不应该是
字符串
,而是它在历史上不应该是字符串。

它的基本原理是,这些不应该是正确的:

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

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

符号总是相同的对象,而文本不是。

另一个考虑因素是
“苹果”。每个字符都有意义,但
:苹果。每个字符都没有意义。字符串是“有序字符列表”,但符号是没有显式值的原子数据点


我想说,
hashwithindifferencetaccess
实际上证明了Ruby符号正在履行两个不同的角色;符号(本质上类似于其他语言中的枚举)和插入字符串(本质上是一种先发制人的优化,补偿了ruby被解释为没有智能优化编译器的优点的事实。)

如果字符串可以继承符号,因为它添加了很多功能(变异). 但符号永远不能“作为”字符串使用,因为在所有需要变异的情况下,它都会失败


在任何情况下,正如我上面所说,string==symbol决不能像上面所建议的那样返回true。如果您仔细考虑一下,您会注意到,在同时考虑子类实例的类中,不可能有==的合理实现。

好问题!我记得当我开始学习ruby时,这个问题一直困扰着我。然而,随着时间的推移,我忘记了+1是正确使用“乞求问题”(这是一个通常清晰且表达良好的问题)
{apples:10}[“apples”]
应该是10吗?所以
{1=>“foo”}[1.0]
应该是
“foo”
,因为您提到了
Fixnum
Float
作为类的示例,在这些类中它是“正确的”?我很困惑。在你的第一段中,你给出了一个非常详细的解释,为什么符号和字符串从根本上是不同的,完全不同的,彼此完全不同。然后,在第二段中,你声称它们几乎相同?Jörg,它们的相似之处在于,如果符号不存在,它们的功能几乎可以通过使用(冻结的)字符串完全复制。它们在语义上是不同的,但在功能上却非常相似,对于大多数新来者来说,它们之间没有联系是令人惊讶的。就像JavaScript没有整数类型(所有JS数字都是浮点)一样,Ruby