在 Ruby 中 Symbol 表示“名字”,比如字符串的名字,标识符的名字,创建一个 Symbol 对象的方法是在名字或者字符串前面加上冒号:
在 Ruby 中每一个对象都有唯一的对象标识符(Object Identifier),可以通过 object_id 方法来得到一个对象的标识符。例子如下:
2327458
3irb(main):002:0> puts :foo.object_id
4327458
5irb(main):003:0> puts :"foo".object_id
6327458
7irb(main):004:0> puts "foo".object_id
824303850
9irb(main):005:0> puts "foo".object_id
1024300010
11irb(main):006:0> puts "foo".object_id
1224296170
前三行语句中的 :foo (或者 :"foo")都是同一个 Symbol 对象,其 object id 为327458,而后三行中的字符串”foo”都是不同的对象,其 object id 依次为24303850、24300010、24296170。
可见,每个 String 对象都是不同的,即便他们包含了相同的字符串内容;而对于 Symbol 对象,一个名字(字符串内容)唯一确定一个 Symbol 对象(Symbol 对象的字符串中不能含有’\0’字符)。
除了可以采用一般的字符串,还可以使用操作符(例如+, -, *, /),变量,常量,方法甚至类的名字来创建 Symbol 对象,例如:+就是一个合法的 Symbol 。实际上,在 Ruby 内部操作符、变量等名字本身就是作为 Symbol 处理的,例如当你定义一个实例变量时, Ruby 会自动创建一个 Symbol 对象,例如 @test 对应为 :@test 。
2
3class Test
4 attr_accessor :test
5end
Symbol 对象和 String 对象是完全不同的东西,对象标识符很明确的说明了这一点。
使用 to_s 或 id2name 方法将 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 已经存在,则直接返回。
2=> :test
3irb(main):002:0> var2 = "test".intern
4=> :test
5irb(main):003:0> var1 == var2
6=> true
7irb(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 。
下面这个哈希表表示按城市分类的一些机器的集合:
2 'beijing' => 'machine1',
3 'shanghai' => 'machine2',
4 'guangzhou' => 'machine3',
5 'tianjin' => 'machine4',
6 'shenzhen' => 'machine5'
7 }
如果要引用 beijing 的机器,使用 hosts['beijing'] 。但如果我们程序中要频繁引用哈希表中 value ,这样就不大好了,因为 Ruby 对每一次字符串引用都会生成一个 String 对象,
累积下来这个开销是相当大的,我们可以使用 Symbol 作为 key:
hosts = { :beijing => 'machine1', :shanghai => 'machine2', :guangzhou => 'machine3', :tianjin => 'machine4', :shenzhen => 'machine5' }
通常我们定义的函数的参数的个数和顺序是写死的,调用函数的时候要确保参数的个数、顺序匹配,有时候这样很不方便,使用哈希参数可以解决这个问题。
products = {: "0001" => "手机" ,: "0002" => "电脑" } |
puts products[: "0001" ] |
使用哈希参数的方法调用②
def my_method(p1,p2,options={})
puts p1
puts p2
options.each{|key,value| puts "#{key} is #{value}"}
end
my_method("1","2",:title=>"标题",:id=>123)