2016-10-24 25 views
1

我想了解此代碼。爲什麼它返回Hello而不是Howdy!類方法正在訪問實例變量

class Speaker 
    @message = "Hello!" 

    class << self 
    @message = "Howdy!" 

    def speak 
     @message 
    end 
    end 
end 

puts Speaker.speak 

回答

-1

此代碼返回「你好」的原因是,它正試圖在一個類< <自身塊來改變一個實例變量。

類方法適用於任何不處理該類的單個實例的任何事物 - 實例變量與類的各個實例相關聯,並且我們無法在類級別更改實例變量。

而不是在說方法中使用實例變量,我們應該使用類變量(用@@表示)。

作爲一個例子,下面的代碼將返回'你好!' -

class Speaker 
    @@message = "Hello!" 

    class << self 
     @@message = "Howdy!" 

     def speak 
      @@message 
     end 
    end 
end 

puts Speaker.speak 
+2

上面的'@ message'是一個類級別的實例變量,它屬於'Speaker'類,它本身作爲一個對象是類'Class'的一個實例:'Speaker.class#=> Class','Speaker .instance_variables#=> [:@message]' –

4

首先,你的消息@message不是一個實例變量,或者更確切地說,沒有實例變量,你可能會思考型:這是一個類級別的實例變種,所以Speaker本身就是一個實例變量,其作爲對象是類Class的實例。

下面的代碼的版本,那麼你想要什麼有局部變量和閉合的事情:

class Speaker 
    @message = "Hello!" 

    class << self 
    message = "Howdy!" 
    define_method(:speak) { message } 
    end 
end 

Speaker.speak 
#=> "Howdy!" 

,這裏是一些代碼,說明類級別的實例變量之間的差異一個「正常」的實例變量:

class Speaker 
    @message = 'Howdy!' # class-level instance variable 

    def initialize 
    @message = 'Hello!' # instance variable of Speaker's instances 
    end 

    def speak 
    @message 
    end 

    class << self 
    def speak 
     @message 
    end 
    end 
end 

Speaker.speak 
#=> "Howdy!" 
Speaker.new.speak 
#=> "Hello!" 
3

這裏是你的代碼,但我已經定義通常的方式(def self.speak...)類方法。由於類方法不過是在類的單例類上定義的實例方法,所以這種更改僅僅是創建相同類方法的不同方式。 (如果你懷疑這種情況,請在兩種方式下運行代碼。)我做了這個改變,因爲我認爲這會讓我解釋清楚的事情。我還添加了一個puts聲明。

class Speaker 
    @message = "Hello!" 

    def self.speak 
    puts "self=#{self}" 
    @message 
    end 

    class << self 
    @message = "Howdy!" 
    end 
end 

類定義的第一行創建一個類的實例變量@message

Speaker.instance_variables 
    #=> [:@message] 
Speaker.instance_variable_get(:@message) 
    #=> "Hello!" 

通過constrast,

@message = "Howdy!" 

上創建Speaker的單件類的一個實例變量:

Speaker.singleton_class.instance_variables 
    #=> [:@message] 
Speaker.singleton_class.instance_variable_get(:@message) 
    #=> "Howdy!" 

現在在Speaker調用speak

Speaker.speak 
    # self=Speaker 
    #=> "Hello!" 

由於self #=> Speakerspeak顯然是返回類實例變量的值。

對於speak返回上Speaker的單個類中定義的實例變量的值,我們可以寫出如下:

class Speaker 
    @message = "Hello!" 

    def self.speak 
    puts "self=#{self}" 
    puts "singleton_class = #{singleton_class}" 
    singleton_class.instance_variable_get :@message 
    end 

    class << self 
    @message = "Howdy!" 
    end 
end 

puts Speaker.speak 
    # self=Speaker 
    # singleton_class = #<Class:Speaker> 
    # Howdy! 

在最後一個表達式,因爲self等於Speakerself是隱含的接收器時沒有明確的接收方,"singleton_class相當於Speaker.singleton_class