2016-10-24 15 views

Antwort

-1

Der Grund dieser Code ‚Hallo‘ gibt, ist, dass es versucht, eine Instanz-Variable in einer Klasse < < Selbstblock zu ändern.

Klassenmethoden sind für alles, was nicht mit einer einzelnen Instanz dieser Klasse zu tun hat - Instanzvariablen sind an einzelne Instanzen einer Klasse gebunden, und wir können Instanzvariablen nicht auf Klassenebene ändern.

Anstatt eine Instanzvariable in der speak-Methode zu verwenden, sollten wir eine Klassenvariable verwenden (gekennzeichnet durch @@).

Als Beispiel gibt der folgende Code "Howdy!" -

class Speaker 
    @@message = "Hello!" 

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

     def speak 
      @@message 
     end 
    end 
end 

puts Speaker.speak 
+2

'@ message' oben ist eine Instanzvariable auf Klassenebene, sie gehört zur Klasse' Speaker', die selbst als Objekt eine Instanz der Klasse 'Class' ist:' Speaker.class # => Class', 'Speaker .instance_variables # => [: @message] ' –

4

First off, Ihre Nachricht @message ist keine Instanzvariable oder vielmehr nicht die Art von Instanzvariablen Sie denken können: es ist eine Klasse-Level-Instanz var, so eine Instanzvariable von Speaker selbst, welches als Objekt eine Instanz der Klasse Class ist.

Hier ist eine Version des Codes, das tut, was Sie mit einer lokalen Variablen und einem Verschluss zu tun versuchen:

class Speaker 
    @message = "Hello!" 

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

Speaker.speak 
#=> "Howdy!" 

Und hier sind einigen Code, der die Differenz zwischen dem Klasse-Level-Instanz-Variable darstellt und ein „normales“ Instanzvariable:

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

Hier ist der Code, außer ich die Klassenmethode in der üblichen Weise definiert habe (def self.speak...). Da eine Klassenmethode nichts anderes als eine Instanzmethode ist, die für die Singleton-Klasse der Klasse definiert ist, ist diese Änderung lediglich eine andere Möglichkeit, dieselbe Klassenmethode zu erstellen. (Wenn Sie das bezweifeln, führen Sie den Code in beiden Richtungen aus.) Ich habe diese Änderung vorgenommen, weil ich dachte, dass dies meine Erklärung des Geschehens klarer machen würde. Ich fügte auch eine puts Erklärung hinzu.

class Speaker 
    @message = "Hello!" 

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

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

Die erste Zeile der Klassendefinition erstellt eine Klasseninstanzvariable @message:

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

von constrast,

@message = "Howdy!" 

eine Instanzvariable auf Speaker ‚s Singletonklasse erstellt:

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

aufrufen Jetzt speak auf Speaker:

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

Als self #=> Speaker, speak offensichtlich den Wert der Klasse Instanzvariablen zurück.

Für speak den Wert der Instanzvariablen auf Speaker ‚s Singletonklasse definiert zurückzukehren wir folgendes schreiben:

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! 

Im letzten Ausdruck, weil selfSpeaker gleich und self ist die implizite Empfänger, wenn Es gibt keinen expliziten Empfänger, "singleton_class entspricht Speaker.singleton_class.

Verwandte Themen