Ruby Symbol(ruby中的冒号) 与 ruby string 区别

转载 2013年12月02日 12:12:50

转自:http://blog.csdn.net/besfanfei/article/details/7966850

Symbol 是什么

Ruby 是一个强大的面向对象脚本语言(本文所用 Ruby 版本为1.8.6),在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字。

创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号


创建 symbol 对象

                
:foo
:test 

 

:”abc

:”I am a boy”

 

你可能会问,字符串就是字符串,干吗还有字符串的名字?这是因为在 Ruby 中字符串也是一种对象,即String 对象。无论其结构还是操作和 Symbol 对象都是不同的。

在 Ruby 中每一个对象都有唯一的对象标识符(ObjectIdentifier),可以通过 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

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 之间转换。

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 对象。

String转化为 Symbol

除了在字符串前面加冒号,还可以使用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>

 

 

使用 Symbol

正如前边提到的, Ruby 内部一直在使用 Symbol ,比如 Ruby 程序中的各种名字,Symbol本质上是 Ruby 符号表中的东西。使用 Symbol 处理名字可以降低 Ruby 内存消耗,提高执行速度,这点我们在下一篇文章中会看到。

那么 Symbol 对我们有什么用呢?当然也是内存。使用String 的开销太大了,因为每一个String都是一个对象。想想前边的例子,一个字符串每出现一次 Ruby 就会创建一个String 对象。

通常来讲,当你面临 String 还是 Symbol 的选择时,可以参考以下标准:

  • 如果使用字符串的内容,这个内容可能会变化,使用 String
  • 如果使用固定的名字或者说是标识符,使用 Symbol

那么什么时候我们会用到名字呢?很多时候都会,比如枚举值、关键字(哈希表关键字、方法的参数)等等

作为哈希表的 key

哈希表是 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



学习后感觉:在项目逐渐做大的时候果然还是要考虑系统的开销问题,冒似现在的自动化项目应该要开始考虑这些事了!

Ruby String常用函数

1、 单引号中的字符串 单引号的字符串中,连续两个\会被一个\替换 例: ‘nds\\’  #->  nds\ ‘nds\\\’  #-> 出错 ‘nds\\\y’  #->  nds\\y...
  • dazhi_100
  • dazhi_100
  • 2013年07月25日 20:52
  • 8266

快速读懂Ruby代码问答

发信人: FenRagwort (Secluded Life), 信区: Ruby  标  题: 快速读懂Ruby代码问答  发信站: 水木社区 (Sun Sep 11 23:05:27 2011...
  • wide288
  • wide288
  • 2014年07月11日 17:10
  • 3168

Ruby对象模型 -整理

本文尚不完善,将会在本月24号前更新 首先,需要先搞清楚Class, Module, Object,Kernel的关系 【转】 Module是Class的父类. Class, Module,...
  • laxse
  • laxse
  • 2016年10月22日 02:17
  • 327

【Ruby】Ruby和Java比较——方法访问权限

最近开始接触Ruby,发现语法很有特点,而大家都喜欢拿Java和Ruby进行比较,本文着重对类方法作用域进行介绍,包括public、protected、private和default。...
  • sunset108
  • sunset108
  • 2015年09月13日 11:54
  • 830

Ruby中单引号和双引号的区别

Ruby中使用引号括起字符表示字符串,但单引号和双引号有所不同。 1. 单引号所括的内容不会做转义,直接就是字符串的内容。如:  Ruby Code  1 puts 'th...
  • LUCIEN06
  • LUCIEN06
  • 2014年01月05日 16:15
  • 1021

ruby 字符串操作

也许String对象最重要的操作就是通过[]下标访问操作了,你可以通过这种方式提取字符串内容或者更改字符串内容。在Ruby1.8中字符串被当作一个字节或者8位的字符码数组,你可以通过length或者s...
  • EI__Nino
  • EI__Nino
  • 2014年10月03日 00:47
  • 3067

ruby中对字符串的操作

创建字符串 在Ruby中创建一个字符串有多种方式。可以有两种方式表示一个字符串:用一对单引号包围字符('str')或用一对双引号包围字符("str") 这两种形式的区别在于对于包围的字符串的处理,用...
  • liwenhjuan
  • liwenhjuan
  • 2014年02月14日 11:05
  • 2838

Ruby中的chop和chomp用法辨析

还没开始系统性的学习Ruby,最近在看metasploit框架的exploit会涉及到Ruby脚本,也就硬着头皮一遍查阅资料一遍做些笔记吧。    Ruby字符串中存在chop和chomp的内置函数...
  • bnxf00000
  • bnxf00000
  • 2015年02月23日 10:27
  • 2835

Cocoapods安装和使用及Ruby环境安装

作为iOS程序员,掌握 CocoaPods 的使用是必不可少的基本技能,它能帮助我们很好的管理第三方框架,减轻我们的工作,操作和安装起来也都很简单。 在安装CocoaPods之前,首先要在本地安...
  • jnbbwyth
  • jnbbwyth
  • 2016年07月15日 09:05
  • 1043

更新ruby镜像

OS EI Capitan无法安装cocoapods和ruby2.3.1,填坑。 字数715 阅读45 评论0 喜欢0 今天工作之余心情不错,想从github上下载个饭否第三方客户端下...
  • SpringJustin
  • SpringJustin
  • 2016年07月06日 10:20
  • 2562
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Ruby Symbol(ruby中的冒号) 与 ruby string 区别
举报原因:
原因补充:

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