我第一次尝试学习Ruby是在2年前,现在我又开始了。我停止的原因是因为我无法理解Symbol类。而现在我再次处于同一点,完全迷失在何时以及为何使用Symbols。我已经阅读了Stackoverflow上的其他帖子以及Googled的几个解释。但我还不明白。
首先,我认为符号只是一种创建某种“命名常量”的方法,而不必像Java那样经历相同的过程。
:all
而不是使用任意值public static final String ALL = 8;
然而,当你在例如使用它时没有多大意义。 attr_accessor :first_name etc.
符号只是一个轻量级的String类吗?我在理解如何解释,何时以及如何在我自己的类和框架中使用符号时遇到了问题。
答案 0 :(得分:35)
简而言之,符号是轻量级字符串,但它们也是不可变的,不可垃圾回收。
你应该不在数据处理任务中将它们用作不可变的字符串(记住,一旦创建了符号,就不能销毁它)。您通常使用符号来命名。
# typical use cases
# access hash value
user = User.find(params[:id])
# name something
attr_accessor :first_name
# set hash value in opts parameter
db.collection.update(query, update, multi: true, upsert: true)
我们来看第一个例子,params[:id]
。在一个中等大的rails应用程序中,可能有数百/数千个散布在代码库周围的应用程序。如果我们使用字符串params["id"]
访问该值,则表示每次都要进行新的字符串分配(之后需要收集该字符串)。在符号的情况下,它实际上到处都是相同的符号。内存分配器,垃圾收集器甚至是你的工作量减少(:
的输入速度比""
更快)
如果你的代码中经常出现一个简单的单字符串,并且你没有做任何时髦的事情(插值,gsub,upcase等),那么它很可能成为一个符号。< / p>
但是,这是否仅适用于作为实际程序逻辑的一部分使用的文本,例如命名,而不是实际运行程序时获得的文本...例如来自用户/ Web等的文本?
我想不出一个我想要将数据从用户/ web转换为符号的情况(除了解析命令行选项之外)。主要是因为后果(一旦创造了符号永远存在)。
此外,许多编辑器为符号提供不同的着色,以在代码中突出显示它们。看一下这个例子
答案 1 :(得分:11)
O'Reilly Ruby Cookbook (第15页)引用Jim Weirich的话说:
符号通常用作散列键,因为它是重要键的标识。使用某些方法传递消息时也需要符号,例如 Object#send 。
答案 2 :(得分:8)
Ruby实现通常有一个表,用于存储所有类,方法和变量的名称。它指的是表中位置的方法名称,避免了昂贵的字符串比较。但您也可以使用此表并为其添加值:symbols
。
如果您编写的代码使用字符串作为标识符而不是文本内容,请考虑使用符号。如果您编写的方法要求参数为“男性”或“女性”,请考虑使用:male
和:female
。比较两个符号的相等性比字符串更快(这就是符号构成好的哈希键的原因)。
答案 3 :(得分:5)
符号用于命名语言中的东西:类的名称,方法的名称等。 这些非常类似于字符串,除了它们永远不会被垃圾收集,并且对相等性的测试被优化为非常快。
Java实现有一个非常类似的东西,除了它不适用于运行时使用。我的意思是,当你编写像obj.someMethod(4)
这样的java代码时,字符串'someMethod'被编译器转换为嵌入在.class文件中的查找表中的符号。这些符号类似于“特殊”字符串,它们不是垃圾收集的,并且可以非常快速地比较相等性。这几乎与Ruby相同,只是Ruby允许您在运行时创建新符号,而Java只允许在编译时使用它。
这就像创建新方法一样 - Java允许它在编译时; Ruby允许它在运行时使用。
答案 4 :(得分:1)
在删除了ruby 2.2版本的符号GC之后,现在,凡人符号,即当我们将字符串转换为符号(“ mortal” .to_sym)时,都会从内存中清除该信息。
检查一下:
require 'objspace'
ObjectSpace.count_symbols
{
:mortal_dynamic_symbol=>3,
:immortal_dynamic_symbol=>5,
:immortal_static_symbol=>3663,
:immortal_symbol=>3668
}