在 關於 self 中,討論過不同環境中,self代表的物件,在學到模組之後,再來看看self於模組中不同區域的意涵。
先前說過類別是物件,每個被定義的類別都是Class的實例,實際上模組也是物件,每個被定義的模組都是Module的實例。例如:
>> module M1; end
=> nil
>> M1.class
=> Module
>>
=> nil
>> M1.class
=> Module
>>
實際上,Class的父類別是Module,而Module則是Class的實例,那是先有Module還是先有Class?這感覺好像是雞生蛋或蛋生雞的問題。例如:
>> Class.superclass
=> Module
>> Module.class
=> Class
>> Class.superclass.class
=> Class
>> Class.superclass.class.superclass
=> Module
>> Class.superclass.class.superclass.class
=> Class
>> Class.superclass.class.superclass.class.superclass
=> Module
>>
=> Module
>> Module.class
=> Class
>> Class.superclass.class
=> Class
>> Class.superclass.class.superclass
=> Module
>> Class.superclass.class.superclass.class
=> Class
>> Class.superclass.class.superclass.class.superclass
=> Module
>>
因為Class與Module是以C撰寫,類似地,Class也是類別,Class本身就是Class的實例化。
Class的父類別是Module,類別可以實例化,但模組不能實例化,除此之外,類別中可以定義的東西,模組中幾乎都可以定義。例如定義模組的模組方法:
>> module M1
>> puts self
>> def self.some
>> puts "some"
>> end
>> end
M1
=> nil
>> M1.some
some
=> nil
>> def M1.other
>> puts self
>> end
=> nil
>> M1.other
M1
=> nil
>>
>> puts self
>> def self.some
>> puts "some"
>> end
>> end
M1
=> nil
>> M1.some
some
=> nil
>> def M1.other
>> puts self
>> end
=> nil
>> M1.other
M1
=> nil
>>
在模組本體中,self代表模組本身,因此若要定義模組方法,可以用self取代實際模組名稱,在模組方法中,self也是代表模組本身,因此模組方法就是屬於模組,類別include模組後,無法使用模組方法:
>> class Some
>> include M1
>> end
=> Some
>> Some.some
NoMethodError: undefined method `some' for Some:Class
from (irb):15
from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>
>> include M1
>> end
=> Some
>> Some.some
NoMethodError: undefined method `some' for Some:Class
from (irb):15
from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>
這跟類別中定義類別方法,而子類別繼承後可以直接使用類別方法有點不同:
>> class Some
>> def self.some
>> puts self
>> end
>> end
=> nil
>> class Other < Some; end
=> nil
>> Other.some
Other
=> nil
>> Some.some
Some
=> nil
>>
>> def self.some
>> puts self
>> end
>> end
=> nil
>> class Other < Some; end
=> nil
>> Other.some
Other
=> nil
>> Some.some
Some
=> nil
>>
子類別可以呼叫父類別中定義的類別方法,若是以父類別呼叫類別方法,則self代表父類別,若是以父類別呼叫類別方法,則self代表父類別。
如果模組中定義實例方法,由於模組無法實例化,因此被定義的實例方法,一定得被include至類別,利用該類別實例化後才能呼叫。例如:
>> module M1
>> def some
>> puts self
>> end
>> end
=> nil
>> class Some
>> include M1
>> end
=> Some
>> s1 = Some.new
=> #<Some:0x262dbe0>
>> s1.some
#<Some:0x262dbe0>
=> nil
>> s2 = Some.new
=> #<Some:0x249c540>
>> s2.some
#<Some:0x249c540>
=> nil
>>
>> def some
>> puts self
>> end
>> end
=> nil
>> class Some
>> include M1
>> end
=> Some
>> s1 = Some.new
=> #<Some:0x262dbe0>
>> s1.some
#<Some:0x262dbe0>
=> nil
>> s2 = Some.new
=> #<Some:0x249c540>
>> s2.some
#<Some:0x249c540>
=> nil
>>
可以看到,模組中定義實例方法時,self並不代表任何物件,只有在被include至類別並實例化後,self代表的物件,就是被實例化的物件。
一個可能會被誤會的是,如果程式區塊中撰寫self,那self代表誰呢?不是程式區塊右邊的訊息接收者,而是看程式區塊外self代表誰。例如:
>> class Some
>> def self.some
>> puts self
>> 3.times { puts self }
>> end
>> end
=> nil
>> Some.some
Some
Some
Some
Some
=> 3
>> class Other
>> def other
>> puts self
>> 3.times { puts self }
>> end
>> end
=> nil
>> o = Other.new
=> #<Other:0x1f98408>
>> o.other
#<Other:0x1f98408>
#<Other:0x1f98408>
#<Other:0x1f98408>
#<Other:0x1f98408>
=> 3
>>
>> def self.some
>> puts self
>> 3.times { puts self }
>> end
>> end
=> nil
>> Some.some
Some
Some
Some
Some
=> 3
>> class Other
>> def other
>> puts self
>> 3.times { puts self }
>> end
>> end
=> nil
>> o = Other.new
=> #<Other:0x1f98408>
>> o.other
#<Other:0x1f98408>
#<Other:0x1f98408>
#<Other:0x1f98408>
#<Other:0x1f98408>
=> 3
>>