当前位置: 代码迷 >> 综合 >> 理解Ruby中的标志(Understanding Ruby Symbols)
  详细解决方案

理解Ruby中的标志(Understanding Ruby Symbols)

热度:45   发布时间:2023-12-06 17:35:45.0
理解Ruby中的标志(Understanding Ruby Symbols)
原文出处:http://glu.ttono.us/articles/2005/08/19/understanding-ruby-symbols
翻译:Suninny AT Gmail.com

标志在Ruby中是一个迷。我们用她,但多数人并不真正懂她。
什么是标志?
简单来说,标志是你用来代表名字或字符串的一个东西。这可以归结为一种高效的描述名--产生单一的字符串用于每个命名实例,这样就节省了空间。
琼斯博士的案例
琼斯博士(Dr Jones)是个心理学家。 他通常使用语词联想试验诊断患者,并且使用Ruby记录一切。 他的第一名患者Why来到了这里:

Dr J: Red
Why : Ruby
Dr J: Transportation
Why : Rails
Dr J: Chunky
Why : Bacon

琼斯博士建立一个散列来存储这些数据:

 why = {"red" => "ruby", "transportation" => "rails", "chunky" => "bacon"}

问题所在

在进行几百个语词联想试验之后,琼斯博士开始意识到他用尽了内存! 于是琼斯在irb进行测试:

> patient1 = { "ruby" => "red" }
> patient2 = { "ruby" => "programming" }
> patient1.each_key {|key| puts key.object_id.to_s}
211006
> patient2.each_key {|key| puts key.object_id.to_s}
203536

我们看到,每次他建立一个散列来存储信息,Ruby就在不同的内存位置为每个键建立了一个新的字符串对象。

幸运的是,我们还有其他的方法。

用标志来突围

不同于字符串,在一个Ruby会话期间,同一个名称的标志只作一次初始化然后就存在于内存中。当你需要重用字符串来表示其他东西时,标志是再适合不过的了。重做琼斯博士的测试,我们能直接观察到:

> patient1 = { :ruby => "red" }
> patient2 = { :ruby => "programming" }
> patient1.each_key {|key| puts key.object_id.to_s}
3918094
> patient2.each_key {|key| puts key.object_id.to_s}
3918094

通过使用标志,在语词联想试验中我们用单一的内存地址代表了“ruby”这个单词。随着时间的推移,这能节省下大量的空间。
标志的其他应用场合
无论何时,只要你是重用一个单词来反复代表其他东西,标志就能派上用场。不管是散列中的一个键,还是Http查询中的一个方法。在最新、最伟大的Web框架--Ruby on Rails的路由和链接中就应用到了标志。

在表现一个网页之前,Rails会执行框架内部的控制器(controllers)中定义的动作(actions),因此在Rails中,链接就像这样表示:

link_to("View Article", :controller => "articles", :action => "show", :id => 1)

当一个应用可能至少有数百个链接,或者说有数百个不同动作和控制器的引用时,使用标志就比使用字符串高效得多。

最后,值得注意的是标志的应用场合并不局限于散列中的键。例如,如果你写一个Http客户端(或服务器),在这个程序中,可能需要多次用到get和post:

do_this if query == :get

...
send_message_to_server(:post,filename)

当需要反复用到一个字符串时,标志或许是一个蛮不错的替代品。

更新
在Freenode(译注:一个著名的IRC服务器)的ruby-lang频道,Aria和Nome为这篇文章给出了有用的增补。

11:58 < Aria> 同样,即便完全出于现实方面的考虑,使用标志也很理想:如果你要引用一个方法名,就用标志吧,因为她总会在那里(在定义了方法之后)。
12:03 < nome> Kevin Clark:标志的目的是用来辨别构造(主要是用户级的):散列中的槽、一个方法、一个选项等等。

同样,Aria还回应了Geoff在注解中提出的问题:

Geoff:我很想知道1000个字符串"red"究竟要比:red耗费多少内存。记住,在Rails之外,"red" != :red

Aria:多少内存?20字节/对象,加上存储数据的3个字节,再加上存储长度的4个字节,一共是27×1000=27000个字节。与此相对,标志表条目的一份拷贝,只需几个字节。

Jim Weirich 写到:
我通常有下面的法则来比较字符串和标志:
(1) 如果侧重于对象的内容(即字符序列),就用字符串;
(2) 如果侧重于对象的身份,就用标志。