我理解字符串和符号在理论上的区别。我知道符号是用来表示一个概念、一个名字、一个标识符、一个标签或一个键,而字符串就是一大堆字符。我知道字符串是可变的和暂时的,其中符号是不可变的和永久的。我甚至喜欢我的文本编辑器中符号与字符串的不同之处。
让我困扰的是,实际上,符号与字符串是如此相似,以至于它们没有被实现为字符串的事实导致了很多令人头疼的问题。它们甚至不支持鸭子类型或隐式强制,不像其他著名的“相同但不同”的组合,Float和Fixnum。
当然,最大的问题是从其他地方进入Ruby的散列,比如JSON和HTTP CGI,使用的是字符串键,而不是符号键,所以Ruby程序必须竭尽全力提前或在查找时转换这些散列。仅仅是HashWithIndifferentAccess
的存在,以及它在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
要让下一代this开发者不那么困惑,只需这样做:
class Symbol < String
def initialize *args
super
self.freeze
end
(还有许多其他库级别的黑客攻击,但仍然不是太复杂)
另请参阅:
更新:我认为Matz在这里为class Symbol < String
做了很好的解释:http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/9192 (感谢Azolo挖掘了这一点,也感谢Matz的最终撤回)。
发布于 2012-06-18 23:52:02
这个答案与我的original answer截然不同,但我在Ruby邮件列表上遇到了一对interesting threads。(两本书都读得很好)
因此,在2006年的某个时候,matz将Symbol
类实现为Symbol < String
。然后,Symbol
类被剥离,以删除所有的可变性。所以Symbol
实际上是一个不可变的String
。
然而,它被恢复了。The reason given was
尽管它是高度反对DuckTyping的,但人们倾向于在类上使用case,而Symbol < String通常会导致严重的问题。
所以你的问题的答案仍然是:Symbol
类似于String
__,但它不是。
问题不是Symbol
不应该是String
,而是它在历史上不是。
发布于 2012-06-18 23:09:03
我不知道完整的答案,但这里有一个很大的部分:
使用符号作为散列键的原因之一是给定符号的每个实例都是完全相同的对象。这意味着:apple.id
将始终返回相同的值,即使您没有传递它。另一方面,"apple".id
每次都会返回一个不同的id,因为会创建一个新的string对象。
这就是为什么建议将符号作为散列键的原因。当使用符号时,不需要进行对象等价性测试。它可以直接短路到对象标识。
发布于 2012-06-20 07:47:07
另一个需要注意的问题是,"apple".each_char
是有意义的,但是:apple.each_char
没有。字符串是“字符的有序列表”,而符号是没有显式值的原子数据点。
我要说的是,HashWithIndifferentAccess
实际上证明了Ruby符号扮演着两种不同的角色:符号(本质上类似于其他语言中的枚举)和内部字符串(本质上是抢占式优化,弥补了ruby被解释为没有智能优化编译器的好处)。
https://stackoverflow.com/questions/11085564
复制相似问题