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

翻译 2006年06月24日 20:46:00
理解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) 如果侧重于对象的身份,就用标志。

Understanding Ruby Blocks, Procs and Lambdas

Understanding Ruby Blocks, Procs and Lambdas Blocks, Procs and lambdas (referred to as closures i...

Ruby+Watir经验谈: Understanding Watir

使用Watire,主要通过是使用Watir::IE的一个实例来获得页面上的各种元素,比如button,link...,然后你可以对这些元素进行操作,比如点击一个button,点击一个link... ...

Understanding nil?, empty? and blank? in Ruby and Rails

When first learning Ruby and Rails, I often used the methods nil?, empty? and blank? incorrectly. Th...

深入理解 Ruby 关键字 yiald

yield 这个关键字所传达的东西,这也是ruby比较有特色的一个地方 在函数里面的有一条yield语句,到时候执行的时候可以执行函数类外的block。而且这个block可以有自己的context...
  • laxse
  • laxse
  • 2016年10月17日 01:08
  • 131

Ruby中“||=”符号理解

def current_user @current_user ||= session[:user_id] && User.find(session[:user_id]) end 短短...
  • lt_fina
  • lt_fina
  • 2012年09月05日 12:47
  • 355

读书笔记之《七周七语言——理解多种编程范型》Ruby语言学习

正如此书中简介所介绍的一样,作为一个程序员,想要提高自己的编程水平,学习了解各种编程语言是一个很有效的途径。通过吸收各种语言的精髓融入到自己最熟悉的语言代码中去。也许你只是一个Objective-c程...

Ruby中“||=”符号理解

def current_user @current_user ||= session[:user_id] && User.find(session[:user_id]) end短短一行代码,却...
  • li_001
  • li_001
  • 2017年04月06日 11:04
  • 132

Ruby module和class的理解分析

一个class就是一系列方法的集合,这些方法将操作对象的状态(即对象的实例变量) module.rb: require './project' #require porject.rb...

深入理解Ruby语言中的String(1)

Ruby语言中的String是mutable的,不像Java、C#中的String是immutable的。比如: str1="abc" str2="abc" 在J...

理解Ruby的4种闭包:blocks, Procs, lambdas 和 Methods

blocks, Procs, Methods, lambdas(也称闭包)是Ruby中最强大的一部分,用过你就会知道,同时也是最容易迷惑的。 这可能是因为Ruby处理闭包的方式有点怪。更甚的是,Ru...
  • lt_fina
  • lt_fina
  • 2012年09月05日 12:42
  • 520
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:理解Ruby中的标志(Understanding Ruby Symbols)
举报原因:
原因补充:

(最多只允许输入30个字)