2012-07-12 72 views
14

第一次尝试学习Ruby是2年前,现在我又开始了。我停止的原因是因为我无法理解符号类。而现在我又处于相同的地位,完全失去了什么时候以及为什么使用符号。我已阅读了Stackoverflow上的其他帖子以及谷歌搜索几个解释。但我还不明白。使用Ruby符号

首先,我认为符号只是一种创建某种“命名常量”的方法,而不必像在Java中那样通过相同的过程。

:all 

,而不是把一个常数为任意值public static final String ALL = 8;

但是它并没有太大的意义,当你在使用例如它attr_accessor :first_name etc. 符号只是一个轻量级的String类吗?我在理解如何解释,何时以及如何在我自己的类和框架中使用符号方面存在问题。

+10

如果它让你感觉更好,Ruby的创建者本身并不真正理解何时使用字符串以及何时使用符号。 'Class.new.methods'返回1.8的字符串数组,1.9的符号数组返回。 :) – 2012-07-15 23:44:04

+0

[在Ruby中理解符号]可能的重复(http://stackoverflow.com/questions/2341837/understanding-symbols-in-ruby) – 2016-08-30 11:33:39

回答

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等),那么它可能是一个很好的候选符号。

但是,这是否仅适用于作为实际程序逻辑的一部分的文本,如命名,而不是实际运行程序时得到的文本...例如用户/ web等文本?

我想不出一个情况,我想将用户/网页上的数据转换为符号(除了解析命令行选项,也许)。主要是因为后果(一旦创造符号永远活着)。

此外,许多编辑者为符号提供不同的着色,以在代码中突出显示它们。看看这个例子

symbol vs string

+0

因此,有Symbol的原因是String是可变的,因此程序员剩下的就是通过使用不可变类Symbol来增强程序的性能? – LuckyLuke 2012-07-12 08:12:26

+0

您应该**不要**在数据处理任务中将它们用作不可变的字符串(请记住,一旦符号被创建,它就不能被销毁)。您通常使用符号来命名事物。 – 2012-07-12 08:15:15

+0

所以一个符号是一个字符串,其属性等于'static',并且在其他语言中是不可变的? – LuckyLuke 2012-07-12 08:17:50

8

一个Ruby实现通常具有这样存储的所有类,方法和变量名的表。它通过表中的位置引用方法名称,避免了昂贵的字符串比较。但你也可以使用这张表,并为其添加值:symbols

如果您编写的代码使用字符串作为标识符而不是其文本内容,请考虑符号。如果您编写的方法预计参数为“男性”或“女性”,请考虑使用:male:female。比较两个符号的相等性比字符串更快(这就是为什么符号能够产生好的散列键)。

11

O'Reilly的红宝石食谱(第15页)引用吉姆·韦里奇的话说:

  • 如果对象的内容(字符序列)是重要的,使用一个字符串。
  • 如果对象的标识很重要,请使用符号。

符号通常用作散列键,因为它是重要的密钥的标识。当使用某些方法传递消息时,也需要符号,如对象#发送

+0

'对象#发送'确实**不**需要符号。 – 2015-12-09 12:21:34

+1

@SergioTulentsev虽然当前版本的MRI接受此方法的字符串参数,但[早期版本没有](http://ruby-doc.org/core-1.8.7/Object.html#method-i-send)。即便如此,除非实现再次发生变化,#send会将字符串参数转换为符号,因为这是Ruby在内部识别方法名称的方式。您的里程(和具体实施)可能会有所不同。 – 2015-12-09 15:19:16

5

符号用于命名语言中的东西:类的名称,方法的名称等 这些非常像字符串,除非它们永远不会被垃圾收集,并且对等式测试进行了优化,非常快。

Java实现有一个非常类似的事情,除了它不可用于运行时。我的意思是,当你编写像obj.someMethod(4)这样的java代码时,字符串'someMethod'被编译器转换为嵌入在.class文件的查找表中的符号。这些符号就像'特殊'字符串,它们不是垃圾收集的,而且它们的速度相当快。这与Ruby几乎相同,只是Ruby允许您在运行时创建新符号,而Java只在编译时允许它。

这就像创建新的方法 - Java允许它在编译时; Ruby在运行时允许它。