在Ruby中定義的類別,為Class的實例。例如:
>> class Some; end
=> nil
>> Some.class
=> Class
>>
=> nil
>> Some.class
=> Class
>>
如果你如下定義類別:
class Some
def some
puts "some"
end
end
def some
puts "some"
end
end
也可以如下定義相同功能的類別:
>> Some = Class.new {
?> def some
>> puts "some"
>> end
>> }
=> Some
>> Some.new.some
some
=> nil
>>
?> def some
>> puts "some"
>> end
>> }
=> Some
>> Some.new.some
some
=> nil
>>
Class.new時指定的程式區塊是類別定義的本體,程式區塊可以指定程式區塊參數,會傳入建構的Class實例,也就是類別定義本身,在程式區塊中使用self也可以取得Class實例。
>> Class.new { |clz| puts clz; puts self}
#<Class:0x468e70>
#<Class:0x468e70>
=> #<Class:0x468e70>
>>
#<Class:0x468e70>
#<Class:0x468e70>
=> #<Class:0x468e70>
>>
如果Class.new時指定常數作為名稱,那麼常數名稱就會作為類別名稱,如果沒有指定常數作為名稱,那麼就會成為匿名類別(Anonymous class)。例如:
>> Some = Class.new
=> Some
>> Other = Some
=> Some
>> Other
=> Some
>> some = Class.new
=> #<Class:0x27263e8>
>> other = some
=> #<Class:0x27263e8>
>> other
=> #<Class:0x27263e8>
>> other.to_s
=> "#<Class:0x27263e8>"
>> Some.to_s
=> "Some"
>>
=> Some
>> Other = Some
=> Some
>> Other
=> Some
>> some = Class.new
=> #<Class:0x27263e8>
>> other = some
=> #<Class:0x27263e8>
>> other
=> #<Class:0x27263e8>
>> other.to_s
=> "#<Class:0x27263e8>"
>> Some.to_s
=> "Some"
>>
上例中,類別若具有名稱,則會直接顯示名稱,如果是匿名類別,則會顯示實例的十六進位位址表示,在範例中也可以看到,有無指定常數作為名稱,會改變to_s的實作。
Class.new時如果沒有指定方法參數,預設就是繼承Object,可以指定想要繼承的父類別。例如:
>> class Some
>> def self.inherited(clz)
>> puts "Some is inherited by #{clz}"
>> end
>> end
=> nil
>> Class.new(Some)
Some is inherited by #<Class:0x27a2378>
=> #<Class:0x27a2378>
>>
>> def self.inherited(clz)
>> puts "Some is inherited by #{clz}"
>> end
>> end
=> nil
>> Class.new(Some)
Some is inherited by #<Class:0x27a2378>
=> #<Class:0x27a2378>
>>
類別是Class的實例,Class的實例方法,其實也就是類別的類別方法。例如,雖然不建議改變核心類別實作,但確實是可以在Class中定義實例方法,該實作方法將成為所有類別(包括匿名單例類別)都具有的類別方法。例如:
>> class Class
>> def some_class_method
>> puts "some_class_method"
>> end
>> end
=> nil
>> class Some; end
=> nil
>> Some.some_class_method
some_class_method
=> nil
>> class << s
>> some_class_method
>> end
some_class_method
=> nil
>>
>> def some_class_method
>> puts "some_class_method"
>> end
>> end
=> nil
>> class Some; end
=> nil
>> Some.some_class_method
some_class_method
=> nil
>> class << s
>> some_class_method
>> end
some_class_method
=> nil
>>
以上只是示範,實際上如果你想某些類別想共同擁有的類別方法,可以抽離至模組中,再讓類別用包括模組的方式來達到目的。
Class的存在,開啟了其它定義類別的方式,而不一定要用class關鍵字。例如也許你會想要動態地建立類別,名稱可以由使用者輸入:
class Some; end
ARGV.each do |clz_name|
Object.const_set(clz_name, Class.new(Some))
end
ARGV.each do |clz_name|
puts Object.const_get(clz_name).new
end
如果如下輸入,可以從命令列指定類別名稱並建構實例:
>ruby main.rb A B C D E
#<A:0x1fe38b8>
#<B:0x1fe3828>
#<C:0x1fe37b0>
#<D:0x1fe3738>
#<E:0x1fe36c0>
>
#<A:0x1fe38b8>
#<B:0x1fe3828>
#<C:0x1fe37b0>
#<D:0x1fe3738>
#<E:0x1fe36c0>
>
先前談過單例方法與匿名單例類別,其實你也可以想像,Ruby每建立一個物件前,都會先用Class.new建立一個匿名類別,再用該匿名類別建立物件,你定義單例方法時,就是定義在該匿名類別上,而class << object的寫法,開啟的也就是該匿名類別,因此可擁有物件個體性的功能存在。