關於 self


在Ruby中,self代表預設的訊息接收者,不同的範圍或呼叫方式,self代表的物件也不相同。在頂層環境中,self是參考至一個名稱為main的物件,為Object的實例:
>> self.is_a? Object
=> true
>> self
=> main
>> self.instance_of? Object
=> true
>>


在頂層環境中定義方法,相當於在Object類別中定義私有實例方法。例如:
def some
    puts "Some"
end

相當於如下定義:
class Object
    def some
        puts "Some"
    end
    private :some
end

Ruby中呼叫方法時沒有指定訊息接收者,那麼預設的訊息接收者就是self在頂層環境時,self代表Object實例,也因此在頂層環境中定義的方法,可以在類別、方法之中直接呼叫。

不過Ruby中,private方法不需也不能透過self呼叫。例如:
>> def some
>>     puts "some"
>> end
=> nil
>> some
some
=> nil
>> self.some
NoMethodError: private method `some' called for main:Object
        from (irb):13
        from C:/Winware/Ruby192/bin/irb:12:in `<main>'
>>


private方法不需也不能透過self呼叫的唯一例外,是在類別中的方法呼叫指定方法時。例如:
>> class Some
>>     def initialize(value)
>>         self.value = value
>>     end
>>     def value=(v)
>>         @value = v
>>     end
>>     private :value=
>>     def value
>>         @value
>>     end
>> end
=> nil
>> s = Some.new(10)
=> #<Some:0x26eb168 @value=10>
>> s.value
=> 10
>>


在上例的initialize方法中,想呼叫private的value方法將值指定給實例變數@value,由於Ruby中若發現=指定,會將值指定給區域變數,為了區別,這種情況下必須使用self明確指定,是要呼叫value()方法,而不是設定區域變數,如果沒有指定self,就會如下:
>> class Some
>>     def initialize(value)
>>         value = value
>>     end
>>     def value=(v)
>>         @value = v
>>     end
>>     private :value=
>>     def value
>>         @value
>>     end
>> end
=> nil
>> s = Some.new(10)
=> #<Some:0x512208>
>> s.value
=> nil
>>


在單例方法或實例方法中,self代表呼叫方法時逗號左邊的物件。例如:
>> obj = Object.new
=> #<Object:0x25f6c80>

>> def obj.self_id
>>     self.object_id
>> end
=> nil
>> obj.object_id
=> 19904064
>> obj.self_id
=> 19904064
>> class Some
>>     def self_id
>>         self.object_id
>>     end
>> end
=> nil
>> s = Some.new
=> #<Some:0x276e520>
>> s.object_id
=> 20673168
>> s.self_id
=> 20673168
>>


在類別本體中,self代表類別本身(也就是Class實例)。例如:
>> class Some
>>     puts self.object_id
>> end
19600008
=> nil
>> Some.object_id
=> 19600008
>>


所以,在定義類別方法時,可以使用self代替具體的類別名稱。例如:
class Some
    def Some.action
        puts "Some.action"
    end
end

可以改用以下的寫法,如此以後修改類別名稱,就不用特別再修改類別方法前的名稱:
class Some
    def self.action
        puts "Some.action"
    end
end

單例方法、實例方法、類別方法 中談過,類別方法實際上是類別的單例方法,所以在類別方法中,self就是代表類別。例如:
>> class Some
>>     def self.self_id
>>         self.object_id
>>     end
>> end
=> nil
>> Some.object_id
=> 18863088
>> Some.self_id
=> 18863088
>>