Monday, October 20, 2008

(17)Ruby中的Symbol

Symbol称为符号对象,它是由Ruby解析器维护的一个符号表,这个符号表中包含了所有已知的类、方法变量等,这主要是为了避免更多的内存开销。因为在Ruby中的字符串是可变对象,所以每一个字符串都是一个单独的对象即使是有相同内容的字符串他们在内存中的id也是不同的,比如:
s="hello"
puts s.object_id
s2="hello"
puts s2.object_id
你会发现他们的object_id是不同的,这和类似Java这样的语言处理方式是不同的,Java中的字符串是不可变对象,所以如果你在Java中定义两个相同内容的字符串,他们在内容中实际上是占用同一块内存地址。
那么Symbol的作用就是唯一标识一个名字,它占用唯一的一个内存地址。Symbol通过在一个唯一的标识符或者字符串前加冒号(:)来定义:
:symbol                   #定义一个Symbol
:"symbol" # 另一种方式
:'another long symbol' # 如果Symbol对象包含空格,可以用引号包含
s = "string"
sym = :"#{s}" # Symbol对象:string

就像String中使用%q和%Q定义字符串的方式,你也可以用%s加上任意的边界符号来定义一个Symbol。
%s[hello]     # 等同于 :hello

Symbol经常用于方法的反射机制,比如我们经常需要判断一个对象是否有each方法:
o.respond_to? :each

下面这个例子用于判断一个对象是否包含一个特定的方法,如果有,就调用它:
name = :size
if o.respond_to? name
o.send(name)
end

你可以通过intern或者to_sym将一个字符串转换为Symbol,反过来你可以使用to_s或者id2name方法将Symbol转换为字符串:
str = "string"     # 定义一个字符串
sym = str.intern # 转换为 symbol
sym = str.to_sym # 另一种转换方法
str = sym.to_s # 在转换回字符串
str = sym.id2name # 另一个转换成字符串的方法
最后我们来总结一下,拥有相同内容的字符串是不同的对象,但是拥有相同内容的字符串转换成的Symbol是一样的,不同的Symbol内容总是不同的。
如果你的程序中用到了字符串,而这个字符串可能表示的是一个唯一的内容,你应该考虑使用Symbol,所以如果你使用字典对象,那么最好用Symbol作为元素的“键”。
在Ruby1.9中增加了一系列String对象中的方法,比如length,size等等,你可以使用这种方式,实现类似不可变字符串的功能。

No comments: