转自:http://blog.youkuaiyun.com/besfanfei/article/details/7966850
Symbol
Ruby
创建一个
:foo :test |
:”
abc”
:”I am a boy” |
你可能会问,字符串就是字符串,干吗还有字符串的名字?这是因为在
在
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")都是同一个
可见,每个 String对象都是不同的,即便他们包含了相同的字符串内容;而对于
值得注意的是创建
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
class Test
attr_accessor :test
end
|
这个类定义了一个具有读写方法的实例变量 @test 。实际上
注意,类变量 @@test 和实例变量 @test 对应的
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 |
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 Symbol.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
查看 all_symbols
例如,可以通过 []=
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>
|
虽然
使用 to_s 或 id2name方法将
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 对象都是唯一的,因此对一个
除了在字符串前面加冒号,还可以使用to_sym 或 intern 方法将String 转化为
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>
|
正如前边提到的,
那么
通常来讲,当你面临 String 还是
- 如果使用字符串的内容,这个内容可能会变化,使用 String
- 如果使用固定的名字或者说是标识符,使用
Symbol
那么什么时候我们会用到名字呢?很多时候都会,比如枚举值、关键字(哈希表关键字、方法的参数)等等
哈希表是
在ruby中,哈希和数组类似,一个哈希表是一系列 key/value 对的集合,只不过它的 key取值范围更广泛,可以是任何对象,比如正则表达式。但通常我们都会取有意义的 key ,比如 String、Symbol
下面这个哈希表表示按城市分类的一些机器的集合。
hosts{ 'beijing' => 'machine1', 'shanghai' => 'machine2', 'guangzhou' => 'machine3', 'tianjin' => 'machine4', 'shenzhen' => 'machine5' } |
如果要引用 beijing 的机器,使用 hosts['beijing'] 。但如果我们程序中要频繁引用哈希表中 value,这样就不大好了,因为
我们完全可以使用 Symbol ,因为对于这些 key 来讲,我们用的就是名字而已,例如下面hosts[:beijing]
|
hosts = { :beijing => 'machine1', :shanghai => 'machine2', :guangzhou => 'machine3', :tianjin => 'machine4', :shenzhen => 'machine5' } |
哈希参数
通常我们定义的函数的参数的个数和顺序是写死的,调用函数的时候要确保参数的个数、顺序匹配,有时候这样很不方便,使用哈希参数可以解决这个问题。
ROR 中就大量地运用这种方式,也许你已经看到了,到处都是
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 |