- 浏览: 253112 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
wls212:
...
数据库查询优化技巧(MySQL) -
wang1352083:
来看几个实例 1、客户/订单/订单项目 ...
MongoDB Schema Design(MongoDB模式设计)(中文简述版) -
RunUpwind:
感谢,对我很有帮助!
ruby install相关(远程安装时出现HTTP Response 302的解决办法) -
yinmang1215:
不错,感觉这些方面的文档真是稀缺,谢了。
MongoDB+Rails的Demo实现 -
fireflyman:
rake -T
Rake命令大全
理解 Ruby Symbol,第 1 部分
转载地址:http://www.ibm.com/developerworks/cn/opensource/os-cn-rubysbl/
使用 Symbol
简介: Ruby 是一个跨平台完全面向对象的脚本语言,构建在 Ruby 之上的 Web 框架Ruby on Rails(ROR) 正在 web 开发领域得到越来越多的认可。ROR 大量使用了 Ruby 语言特性,Symbol 就是其中之一。通过对 Symbol 对象进行较全面的了解,您可以更好地使用 Ruby 和 ROR。
Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。
创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号:
创建 symbol 对象
:foo :test |
:”
abc”
:”I am a boy” |
你可能会问,字符串就是字符串,干吗还有字符串的名字?这是因为在 Ruby 中字符串也是一种对象,即 String 对象。无论其结构还是操作和 Symbol 对象都是不同的。
在 Ruby 中每一个对象都有唯一的对象标识符(Object Identifier),可以通过 object_id 方法来得到一个对象的标识符。我们来看看 Symbol 对象和 String 对象的差别:
Ruby 对象标识符
irb(main):001:0> puts :foo.object_id 327458 => nil irb(main):002:0> puts :foo.object_id 327458 => nil irb(main):003:0> puts :"foo".object_id 327458 => nil irb(main):004:0> puts "foo".object_id 24303850 => nil irb(main):005:0> puts "foo".object_id 24300010 => nil irb(main):006:0> puts "foo".object_id 24296170 => nil |
可以看到,前三行语句中的 :foo (或者 :"foo")都是同一个 Symbol 对象,其 object id 为327458,而后三行中的字符串”foo”都是不同的对象,其 object id 依次为24303850、24300010、24296170。
可见,每个 String 对象都是不同的,即便他们包含了相同的字符串内容;而对于 Symbol 对象,一个名字(字符串内容)唯一确定 一个 Symbol 对象。
值得注意的是创建 Symbol 对象的字符串中不能含有’\0’字符,而 String 对象是可以的。
非法 Symbol 字符串
irb(main):001:0> :"fo\0o" SyntaxError: compile error (irb):1: symbol cannot contain '\0' from (irb):1 irb(main):002:0> :"foo\0" SyntaxError: compile error (irb):2: symbol cannot contain '\0' from (irb):2 irb(main):003:0> puts "foo\0".object_id 24305140 => nil irb(main):004:0> puts "fo\0o".object_id 24301000 => nil irb(main):005:0> |
除了可以采用一般的字符串,还可以使用操作符(例如+, -, *, /),变量,常量,方法甚至类的名字来创建 Symbol 对象,例如:+就是一个合法的 Symbol 。实际上,在 Ruby 内部操作符、变量等名字本身就是作为 Symbol 处理的,例如当你定义一个实例变量时, Ruby 会自动创建一个 Symbol 对象,例如 @test 对应为 :@test 。
实例变量的 Symbol
class Test attr_accessor :test end |
这个类定义了一个具有读写方法的实例变量 @test 。实际上 Ruby 创建了两个 Symbol ,一个是实例变量的 symbol :@test ,另一个是 :test 。那如果使用字符串对象 ”test” 作为参数呢?也可以,仍然会创建两个 symbol ,:test 和 :@test ,为什么还会创建 :test 呢?这是和Ruby的实现相关的(至少Ruby1.8.6里是这样)。
注意,类变量 @@test 和实例变量 @test 对应的 Symbol 显然是不同的。记住:名字相同,则Symbol 相同 。
名字相同, Symbol 相同
class Test puts :Test.object_id Test = 10 puts :Test.object_id def Test puts :Test.object_id end end Test.new.Test |
运行结果
224298 224298 224298 |
名字不同, Symbol 不同
class Test puts :Test.object_id @@test = 10 puts :@@test.object_id def test puts :test.object_id @test = 10 puts :@test.object_id end end t =Test.new t.test |
运行结果
224298 288068 79858 288108 |
第一个例子里,类名、常量名和方法名都是 Test ,因此相应的 Symbol 对象都是 :Test 。不用担心, Ruby 可以很好区分它在不同上下文中到底表示什么。当然这并不是一个好的编程风格,但对于理解 Ruby 的 Symbol 还是有帮助的: Symbol 表示一个名字,仅此而已。
Symbol 对象一旦定义将一直存在,直到程序执行退出。所有 Symbol 对象存放在 Ruby 内部的符号表中,可以通过类方法 Symbol.all_symbols
得到当前 Ruby 程序中定义的所有 Symbol 对象,该方法返回一个 Symbol 对象数组。由于 Symbol 比较多,你可以 dump 到文件中来查看。
all_symbols 方法
irb(main):001:0> Symbol.all_symbols.size => 4047 irb(main):002:0> Symbol.all_symbols[0..9] => [:@level_notifier, :ppx, :msg_dn, :version, :secs, :@user, :pos, :socketpair, :TkENSURE, :HTTPAccepted] irb(main):003:0> File.open("sym", "w") do |file| file.puts Symbol.all_symbols end => nil |
Symbol 对象和 String 对象是完全不同的东西,对象标识符很明确的说明了这一点。除此之外,我们还可以从两种对象的方法上区分。
查看 Ruby 库参考,你会发现 String 类有非常多的方法,包括 Mixed-in 方法(Ruby中一个类通过 include 其他模块而得到的方法,实现多重继承的效果)、类方法和实例方法;而 Symbol 类只有一个类方法 all_symbols
和7个实例方法。
例如,可以通过 []=
方法改变 string 的内容,而 symbol 则不行:
[]= 方法比较
irb(main):001:0> s="test" => "test" irb(main):002:0> s[0]='1' => "1" irb(main):003:0> puts s 1est => nil irb(main):004:0> sym=:test => :test irb(main):005:0> sym[0]=1 NoMethodError: undefined method `[]=' for :test:Symbol from (irb):5 irb(main):006:0> |
虽然 Symbol 和 String 是不同的对象,但它们之间关系很密切。 Ruby 提供了方法在 Symbol和 String 之间转换。
使用 to_s 或 id2name 方法将 Symbol 转化为一个 String 对象:
Symbol 到 String
irb(main):001:0> :test.id2name => "test" irb(main):002:0> :test.to_s => "test" irb(main):003:0> :"I am a boy".to_s => "I am a boy" |
注意,每个 String 对象都是唯一的,因此对一个 Symbol 调用多次将产生多个 String 对象。
除了在字符串前面加冒号,还可以使用 to_sym 或 intern 方法将 String 转化为 Symbol ,如果该 Symbol 已经存在,则直接返回。
String 到 Symbol
irb(main):001:0> var1 = "test".to_sym => :test irb(main):002:0> var2 = "test".intern => :test irb(main):003:0> var1 == var2 => true irb(main):004:0> |
正如前边提到的, Ruby 内部一直在使用 Symbol ,比如 Ruby 程序中的各种名字,Symbol本质上是 Ruby 符号表中的东西。使用 Symbol 处理名字可以降低 Ruby 内存消耗,提高执行速度,这点我们在下一篇文章中会看到。
那么 Symbol 对我们有什么用呢?当然也是内存。使用 String 的开销太大了,因为每一个String 都是一个对象。想想前边的例子,一个字符串每出现一次 Ruby 就会创建一个 String 对象。
通常来讲,当你面临 String 还是 Symbol 的选择时,可以参考以下标准:
- 如果使用字符串的内容,这个内容可能会变化,使用 String
- 如果使用固定的名字或者说是标识符,使用 Symbol
那么什么时候我们会用到名字呢?很多时候都会,比如枚举值、关键字(哈希表关键字、方法的参数)等等
哈希表是 Symbol 应用最为广泛的地方。
在ruby中,哈希和数组类似,一个哈希表是一系列 key/value 对的集合,只不过它的 key 取值范围更广泛,可以是任何对象,比如正则表达式。但通常我们都会取有意义的 key ,比如 String、Symbol 。
下面这个哈希表表示按城市分类的一些机器的集合。
一个哈希表例子
hosts{ 'beijing' => 'machine1', 'shanghai' => 'machine2', 'guangzhou' => 'machine3', 'tianjin' => 'machine4', 'shenzhen' => 'machine5' } |
如果要引用 beijing 的机器,使用 hosts['beijing'] 。但如果我们程序中要频繁引用哈希表中 value ,这样就不大好了,因为 Ruby 对每一次字符串引用都会生成一个 String 对象,累积下来这个开销是相当大的。
我们完全可以使用 Symbol ,因为对于这些 key 来讲,我们用的就是名字而已,例如下面hosts[:beijing] |
使用 Symbol 作为 key
hosts = { :beijing => 'machine1', :shanghai => 'machine2', :guangzhou => 'machine3', :tianjin => 'machine4', :shenzhen => 'machine5' } |
哈希参数
通常我们定义的函数的参数的个数和顺序是写死的,调用函数的时候要确保参数的个数、顺序匹配,有时候这样很不方便,使用哈希参数可以解决这个问题。
ROR 中就大量地运用这种方式,也许你已经看到了,到处都是 Symbol 和哈希。比如:
使用哈希参数的方法调用
link_to 'Show', :action => 'show', :id => product add_column :products, :price, :decimal, :precision => 8, :scale => 2, :default => 0 |
使用哈希参数的方法可以如下定义,前半部分为固定参数,后面为可变参数,或者干脆全采用哈希参数:
哈希参数
def my_method(para1, …, options={}) #your code end def my_method(options={}) #your code end |
如果你希望设定一些默认参数,并允许调用者更改这些参数,可以使用哈希对象的 merge! 方法
hsh.merge!( other_hash )
。该方法将
other_hash
里内容加到
hsh
中,如果other_hash
与
hsh
有重复的
key
,则
key
在
other_hash
中的
value
覆盖
hsh
中对应
key
的
value
。
方法定义-使用默认参数
class Test def my_method(opts={}) default_opts={:arg1 => 10, :arg2 => "abc"} default_opts.merge!(opts) default_opts.each{|key,value| puts "#{key} is #{value}"} end end t = Test.new t.my_method :arg1=>5, :arg3=>"def" |
运行结果
arg1 is 5 arg2 is abc arg3 is def |
在 Rails 中,对 hash 类进行了扩展,可以使用 reverse_merge! 方法来达到上述效果。该方法在 ActiveSupport::CoreExtensions::Hash::ReverseMerge 中定义。Rails 甚至还提供了 assert_valid_keys 方法,对传递进来的哈希表的 keys 进行合法性检验。
Perl 说,条条大路通罗马。在 Ruby 中也是这样的,也许你会发现更好的应用 Symbol 和哈希的方法。
下篇文章我们将深入 Ruby 内部来看看 Symbol 的样子。
- 在 Ruby 的官方网站可以得到各种 Ruby 信息:下载、文档、社区
- Ruby on Rails(ROR) 的官方网站,你可以浏览 Rails 的方方面面:API 、CoreLib 等
- 在 RubyForge 找到更多 Ruby 开源项目。
- 一个不错的Ruby 学习站点 ,有一些关于 Symbol 的内容。
- 阅读 developerWorks 上的文章“使用Ruby on Rails 快速开发Web 应用程序”
- “Programming in the Ruby language ” (developerWorks) Ruby 编程简介。
- Programming Ruby: The Pragmatic Programmer's Guide 的在线版本。
发表评论
-
symbol与ruby方法中的hash参数
2012-12-05 20:14 1545symbol与ruby方法中的hash ... -
Ruby 数组与hash
2012-12-05 20:09 1884Ruby 数组与hash 【 ... -
ruby&rails博客、网站集锦
2012-02-27 16:27 118#可以在线各种语言的API http://www.gotap ... -
Python, Ruby 与 Groovy,谁与争锋?
2012-02-27 16:28 2723Python, Ruby 与 Groovy,谁 ... -
JRuby简介
2012-02-27 16:28 1620什么是JRuby? 网上搜索的答案\(^o^)/~ 答案 ... -
Ruby1.9中获得字符串ASCII码的方法
2011-06-22 11:43 2256例如,在Ruby1.8中获得字符'A'的ASCII码有如下两种 ... -
Ruby 1.9以后字符串编码方式的变化
2011-06-22 11:36 1921在某次为项目的一个应用程序memy做rake测试时出现了如下的 ... -
ruby1.9中CSV.open的API变化
2011-05-31 15:54 1449参考博文: http://comments.gmane.or ... -
ruby v1.8.6升级到v1.8.7
2011-01-06 18:04 1993环境:Windows 7 升级ruby所用的安装文件:rub ... -
ruby install相关(远程安装时出现HTTP Response 302的解决办法)
2010-12-20 15:09 6701ruby install [转载:http: ... -
ruby读取file
2010-11-17 15:33 2884转载地址: http://my.766.com/space. ... -
ruby&rails博客、网站集锦
2010-11-17 15:23 1567Ruby官网: http://www.ruby-lan ... -
ruby中日期间隔的取得
2010-08-04 09:32 1416参考博客(Ruby中处理时间和日期):http://zarkn ...
相关推荐
解释的不错,应该明确了不少 ruby symbol详解 起因 最近在学习ruby on rails,的确是一个优秀的数据库开发框架。但在过程中,发现在视图文件夹中的rhtml文件里有大量的类似于以下的语句: <td><%= link_...
符号不仅是 Ruby 性能优化的关键组成部分,也是理解 Ruby 核心特性的窗口之一。通过深入了解符号的特性和使用方式,我们可以更好地利用它们来编写更加高效和 Ruby 风格的代码。 #### 符号概述 符号是 Ruby 中一种...
本套官方文档包含了关于Ruby核心库、标准库、语言特性和整体框架的详细信息,是学习和深入理解Ruby不可或缺的参考资料。 《ruby23-stdlib.chm》文档主要涵盖了Ruby的标准库(Standard Library)。Ruby标准库提供了...
### Eloquent Ruby:深入探索Ruby语言的魅力 #### 引言 《Eloquent Ruby》是一本深受Ruby...通过阅读本书,你可以更加深刻地理解Ruby语言的设计理念,掌握其实现复杂功能的方法,并最终成为一名真正的Ruby专家。
通过这个中文手册,开发者不仅可以学习到Ruby的基本语法,还可以了解到更高级的主题,如元编程、闭包、 Blocks、Proc对象和Symbol,以及如何利用Ruby的灵活性来创建高效、简洁的代码。同时,了解RGSS可以让开发者...
Ruby是一种强大的、面向对象的编程语言,以其简洁的语法和灵活的编程理念而...通过阅读"Ruby Trap"电子书,初学者可以对这些潜在的问题有更深入的理解,并学会如何在实际编程中避免这些陷阱,从而更好地掌握Ruby编程。
符号(Symbol)在Ruby中是特殊的,它们在内存中只存在一份,常用于元编程中的键值。 5. **Proc对象与lambda**:Ruby的`Proc`和`lambda`可以创建匿名函数,它们可以被赋值给变量,作为参数传递,或者用作方法的...
1. **变量和数据类型**:Ruby支持多种数据类型,包括整型(Integer)、浮点型(Float)、字符串(String)、布尔型(Boolean)以及符号(Symbol)。此外,Ruby还有数组(Array)和哈希(Hash)等复合数据类型。 2. ...
Ruby是一种流行的开源编程语言,以其简洁、优雅的语法和强大的元编程能力著称。在开发复杂的Web应用程序时,性能监控和故障诊断是确保系统稳定性和高效运行的关键环节。New Relic是一个强大的应用性能管理(APM)...
Ruby的核心理念是“人比计算机更重要”,因此它的设计目标是让代码易于理解,减少程序员的疲劳。 Ruby的语法设计深受Perl和Smalltalk的影响,具有以下特点: 1. **动态类型**:Ruby是动态类型的,这意味着变量的...
1. **可读性和维护性**: 过度使用元编程可能会导致代码难以理解和维护。 2. **性能**: 动态生成代码可能会影响程序的性能。 3. **安全性**: 使用如`eval`这样的方法时需要注意安全性问题。 综上所述,Ruby元编程是...
7. **符号(Symbol)**:Ruby中的符号是不可变的,它们在内存中只存储一份,适用于作为哈希表的键,提高查找效率。 8. **块和 Proc**:Ruby中的块是代码的另一个形式,可以用`do..end`或者花括号`{}`包裹。Proc对象...
在这一版中,作者深入浅出地讲解了Ruby 1.9的改进和新特性,旨在帮助开发者更好地理解和利用这个版本的优势。 1. **Ruby 1.9的关键改进**: - 字符串编码:Ruby 1.9引入了对多种字符编码的支持,使得处理多语言...
本教程的源代码涵盖了以上概念,你可以通过阅读和运行代码来更好地理解Ruby的语法和特性。例如,你可能会找到关于类定义、方法调用、数据结构操作、控制流以及简单的Rails应用示例。 通过深入学习这个Ruby中文教程...
2. **Hash和Symbol的变化**:Ruby-2.1引入了新的Hash实现,提升了哈希表的性能,同时可能对Symbol对象进行了调整,以减少内存消耗。 3. **块和Proc**:Ruby-2.1.10可能增强了对块(block)和Proc对象的处理,包括更...
这份"Ruby学习资料chm"集合了关于Ruby的基础学习材料,对于初学者或是希望深入理解Ruby的人来说是一份宝贵的资源。 Ruby的核心特性包括: 1. 面向对象:在Ruby中,一切都是对象,包括基本的数据类型如整数、字符串...
此外,Ruby 1.9还引入了新的内建数据结构,如Symbol表和Fixnum/Bignum的合并,提高了性能。 Ruby编程语言的核心特性包括: 1. 面向对象:Ruby是一种纯粹的面向对象语言,所有数据都是对象,包括基本类型,如整数和...
它鼓励使用自然语言般的语法,使得代码易于理解和维护。Ruby-2.3.3在之前的版本基础上,继续优化了性能,修复了已知的bug,并引入了一些新的语言特性。 在Ruby-2.3.3中,最显著的新特性包括: 1. **Numeric ...