Ruby中的Symbol类型
Symbol类型
Symbol是Ruby中特有的,称为『符号』,它是不可变对象。对于Symbol,理解它的意义比掌握它的具体用法更重要。
在展现形式上,Symbol的第一个字符使用一个冒号,其它和字符串形式完全相同。事实上String可以转换成Symbol(intern()
方法或to_sym()
方法),Symbol也可以转换成String(to_s()
方法或id2name()
方法),唯一不同的是Symbol前面多了一个冒号。
1 | # Symbol字面量 |
由于Symbol和String的特性不同,它们的使用场景也有很大不同。但仍然有很多场景下它们可以互换使用。
Symbol在Ruby内部的维护
Ruby中的常量名、方法名、变量名、类名等等都是Symbol类型。
由于Symbol是解释器内部维护的全局性的表,所以不同上下文中对名称相同的Symbol对象的引用是同一个对象。例如,在某处定义了常量名GOOD,它是一个Symbol,那么在另一个上下文中如果定义了一个名为GOOD的方法,那么它们引用的对象都是Symbol表中的同一个GOOD对象,只不过它们的意义不一样,一个是常量,一个是方法。
关于Symbol的等同性
对于字符串来说,内容相同的两个字符串可能是不同的字符串对象。
但对于Symbol来说,只要内容相同,那么一定是同一个Symbol对象。反之,内容不同的两个Symbol一定是不同的对象。因为在创建Symbol对象时,首先会根据其内容做一番处理然后存储到Ruby解释器内部维护的Symbol表中。所以,Symbol能保证了唯一性。
Symbol能用来干什么
通常会使用id作为标识符来表示某个东西(对象)的唯一性,id通常也是数值形式的。但是在Ruby中,Symbol可以看作是字符串形式的标识符,只不过这个『字符串』是不可变的。
正如Ruby中的类、方法等都是使用Symbol作为名称标识符的,即能保证唯一性,又能保证检索的高效性。
当使用字符串的目的仅仅只是一种标识而不考虑其内容的变化性,那么可以使用Symbol来取代字符串。
比如,Hash类型的key经常使用Symbol类型。
再例如,某方法中接收一个参数,参数可能是『AM』或『PM』,它们是不变的,就这两种情况,那么可以将该参数定义为Symbol类型。
Symbol的一些常用API
Symbol::all_symbols -> arr
返回Ruby解释器内部维护的Symbol表中所有已定义的Symbol。
1 | Symbol.all_symbols.size #=> 4680 |
to_s
id2name
将Symbol转换成字符串。
sym1 <=> sym2
比较两个Symbol对象的大小,比较的方式是to_s转换成字符串,再对字符串使用<=>
做比较。
casecmp(other_symbol) → -1, 0, +1, or nil
不区分大小写的比较Symbol,而比较是转换成字符串比较的。它是不区分大小写版的<=>
方法。
sym1 == sym2
sym1 === sym2
sym1和sym2是同一Symbol对象时返回true,即它们在字符串上的内容相同时为true。
sym1 =~ OBJ
将sym1先转换成字符串,再做正则匹配。即等价于sym1.to_s =~ OBJ
。一般这个时候的OBJ是正则表达式。
sym[idx]
sym[idx,length]
sym[rng]
slice[idx]
slice[idx,length]
slice[rng]
sym先转换成字符串,然后再索引字符串。例如:
1 | :hello[1..3] #=> "ell" |
capitalize → symbol
capitalize([options]) → symbol
将symbol转换成字符串后改其首字母大小,然后再转换成Symbol。即等价于sym1.to_s.capitalize.to_sym
。
1 | :"last name".capitalize #=> :"Last name" |