Frage

class Hello
@hello = "hello"
    def display
        puts @hello
    end
end

h = Hello.new
h.display

Ich habe die Klasse oben. Es druckt nicht alles aus. Ich dachte, die Instanzvariable @hello während der Klassendeklaration festgelegt wurde. Aber wenn ich die Anzeigemethode nennen, ist der Ausgang ‚entfällt‘. Was ist der richtige Weg, dies zu tun?

War es hilfreich?

Lösung

Instanzvariablen in Ruby kann ein wenig verwirrend sein, wenn die ersten Ruby-Lernen, vor allem, wenn Sie in einer anderen OO-Sprache wie Java gewohnt sind.

Sie können nicht einfach eine Instanz Variable deklarieren.

Eines der wichtigsten Dinge über Instanzvariablen in Ruby kennen, abgesehen von der Notation mit einem @ -Zeichen Präfix, ist, dass sie in dem Leben Frühling das erste Mal, sie zugeordnet sind, .

class Hello
  def create_some_state
    @hello = "hello"
  end
end

h = Hello.new
p h.instance_variables 

h.create_some_state
p h.instance_variables

# Output
[]
["@hello"]

Sie können die Methode Object#instance_variables verwenden, um alle Instanzvariablen eines Objekts aufzulisten.

Sie normalerweise „erklären“ und initialisieren alle Instanzvariablen in der Methode initialize. Eine weitere Möglichkeit, klar zu dokumentieren, die Instanzvariablen, die öffentlich zugänglich sein sollten, ist das Modul Methoden attr_accessor zu verwenden (Lesen / Schreiben), attr_writer (Schreiben) und attr_reader (lesen). Diese Methoden werden verschiedene Zugriffsmethoden für die aufgeführte Instanzvariable synthetisieren.

class Hello
  attr_accessor :hello
end

h = Hello.new
p h.instance_variables 

h.hello = "hello"
p h.instance_variables

# Output
[]
["@hello"]

Die Instanzvariablen noch nicht erstellt werden, bis sie zur Verwendung der synthetisierten Hello#hello= Methode zugewiesen wird.

Ein weiteres wichtiges Thema, wie KCH beschrieben, ist, dass Sie aktiv kennen die unterschiedlichen Kontexten sein müssen, wenn eine Klasse zu deklarieren. Wenn die Deklaration eine Klasse der default Empfänger (Selbst-) in dem äußersten Umfang wird das Objekt, das die Klasse selbst darstellt. Daher Code wird zunächst eine Instanz der Klasse Variable erstellen, wenn sie auf der Ebene der Klassen @hello zuweisen.

Innerhalb Methoden self wird das Objekt, auf dem die Methode aufgerufen wird, also versuchen Sie, den Wert einer Instanzvariable mit dem Namen @hello in dem Objekt zu drucken, das nicht der Fall ist vorhanden ( beachten sie, dass es vollkommen legal ist eine nicht vorhandene Instanz Variable zu lesen).

Andere Tipps

Sie benötigen eine initialize Methode hinzufügen:

class Hello
    def initialize
        @hello = "hello"
    end
    def display
        puts @hello
    end
end

h = Hello.new
h.display

Der erste @hello in Ihrem Code wird eine Instanz der Klasse Variable genannt.

Es ist eine Instanzvariable der Klasse Objekt, das die Konstante Hello Punkte. (Und das ist eine Instanz der Klasse Class.)

Technisch gesehen, wenn Sie innerhalb des class Umfang sind, dann ist Ihr self zum Objekt Ihrer aktuellen Klasse gesetzt und @variables beziehen sich auf Ihren aktuellen self. Boy Ich sauge diese Dinge zu erklären.

Sie können alles bekommen und viel mehr für Sie geklärt durch die Beobachtung diese Sammlung von $ 5 je Screencasts von den Pragmatische Programmierer .

(Sie können auch hier für Klärung fragen, und ich werde versuchen, zu aktualisieren.)

gibt es eine klare Beschreibung in dem Buch „Die Programmiersprache Ruby“, lesen Sie es sehr hilfreich sein wird. Ich füge ihn hier (aus Kapitel 7.1.16):

  

Eine Instanz Variable innerhalb einer Klassendefinition verwendet, aber außerhalb einer   Beispiel Methodendefinition ist eine Klasseninstanzvariable .

class Point
    # Initialize our class instance variables in the class definition itself
    @n = 0              # How many points have been created
    @totalX = 0         # The sum of all X coordinates
    @totalY = 0         # The sum of all Y coordinates

    def initialize(x,y) # Initialize method 
      @x,@y = x, y      # Sets initial values for instance variables
    end

    def self.new(x,y)   # Class method to create new Point objects
      # Use the class instance variables in this class method to collect data
      @n += 1           # Keep track of how many Points have been created
      @totalX += x      # Add these coordinates to the totals
      @totalY += y

      super             # Invoke the real definition of new to create a Point
                    # More about super later in the chapter
    end

    # A class method to report the data we collected
    def self.report
        # Here we use the class instance variables in a class method
        puts "Number of points created: #@n"
        puts "Average X coordinate: #{@totalX.to_f/@n}"
        puts "Average Y coordinate: #{@totalY.to_f/@n}"
    end
end

......

  

Weil Klasse Instanzvariablen sind nur Instanzvariablen der Klasse   Objekte können wir attr, attr_reader und attr_accessor zum Erstellen   Accessormethoden für sie.

class << self
  attr_accessor :n, :totalX, :totalY
end

Mit diesen Accessoren definiert ist, können wir unsere Rohdaten als Point.n beziehen, Point.totalX und Point.totalY.

Ich habe vergessen, dass es eine „Klasseninstanzvariable“ -Konzept in Ruby ist. Auf jedem Fall schien das Problem des OP rätselhaft, und wurde in eine der Antworten bisher nicht wirklich angesprochen, außer um einen entsprechenden Hinweis in KCH Antwort: Es ist ein Problem des Anwendungsbereich ist. (Hinzugefügt am edit: Eigentlich sris Antwort hat Adresse dieser Punkt am Ende, aber ich werde diese Antwort lasse sowieso stehen, wie ich der Beispiel-Code denken könnte für das Verständnis des Problems hilfreich sein.)

In einer Ruby-Klasse, ein Variablenname mit @ beginnen kann auf eine von beziehen sich zwei Variablen: entweder auf eine Instanzvariable oder Klasse Instanzvariable , je nachdem, wo in der Klasse es bezeichnet. Dies ist ein ziemlich subtiler Gotcha.

Ein Beispiel den Punkt klären. Hier ist eine kleine Ruby-Test-Klasse (alle Code in irb getestet):

class T

  @@class_variable = "BBQ"
  @class_instance_variable_1 = "WTF"
  @class_instance_variable_2 = "LOL"

  def self.class_method
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

  def initialize
    @instance_variable = "omg"
    # The following line does not assign a value to the class instance variable,
    # but actually declares an instance variable withthe same name!
    @class_instance_variable_1 = "wtf"
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    # The following two lines do not refer to the class instance variables,
    # but to the instance variables with the same names.
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

  def instance_method
    puts "@@class_variable           == #{@@class_variable           || 'nil'}"
    # The following two lines do not refer to the class instance variables,
    # but to the instance variables with the same names.
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
    puts "@instance_variable         == #{@instance_variable         || 'nil'}"
  end

end

Ich nannte die Variablen nach dem, was ich dachte, sie waren, obwohl das nicht immer erweist sich der Fall sein:

irb> T.class_method
@@class_variable           == BBQ
@class_instance_variable_1 == WTF    # the value of the class instance variable
@class_instance_variable_2 == LOL    # the value of the class instance variable
@instance_variable         == nil    # does not exist in the class scope
=> nil

irb> t = T.new
@@class_variable           == BBQ
@class_instance_variable_1 == wtf    # the value of the instance variable
@class_instance_variable_2 == nil    # the value of the instance variable
@instance_variable         == omg
=> #<T:0x000000015059f0 @instance_variable="omg", @class_instance_variable_1="wtf">

irb> t.instance_method
@@class_variable           == BBQ
@class_instance_variable_1 == wtf    # the value of the instance variable
@class_instance_variable_2 == nil    # the value of the instance variable
@instance_variable         == omg
=> nil

irb> T.class_method
@@class_variable           == BBQ
@class_instance_variable_1 == WTF    # the value of the class instance variable
@class_instance_variable_2 == LOL    # the value of the class instance variable
@instance_variable         == nil    # does not exist in the class scope
=> nil

Die @@class_variable und @instance_variable immer so verhalten, wie man es erwarten würde: Erstere auf Klassenebene definiert ist, und ob in einer Klassenmethode oder in einer Instanz-Verfahren bezeichnet, hält es Wert, um es an der Spitze zugeordnet. Letzteres wird nur ein Wert in einem Objekt der Klasse T, so in einer Klassenmethode, bezieht er sich auf eine unbekannte Variable, deren Wert nil.

Die Klassenmethode namens phantasievoll class_method gibt die Werte der @@class_variable und die beiden @class_instance_variables wie erwartet, das heißt, an der Spitze der Klasse als initialisiert. Doch in den Instanzmethoden initialize und instance_method, andere Variablen mit dem gleichen Namen zugegriffen werden, das heißt, Instanzvariablen, nicht Klasse Instanzvariablen .

Sie sehen, dass die Zuordnung in der initialize Methode nicht die Klasseninstanzvariable @class_instance_variable_1 nicht beeinträchtigte, da der spätere Aufruf von class_method seinen alten Wert ausgibt, "WTF". Stattdessen Methode initialize deklariert eine neue Instanz Variable, ein, das ist auch genannt (misleadingly) @class_instance_variable_1. Der Wert zugewiesen, "wtf", ausgegeben von Methoden initialize und instance_method.

Die Variable @class_instance_variable_2 im Beispielcode zu Variable @hello im ursprünglichen Problem äquivalent: sie als Klasseninstanzvariable initialisiert deklariert und wird, aber wenn eine Instanz-Methode auf eine Variable dieses Namens bezieht, es sieht tatsächlich ein Instanzvariable mit dem gleichen Namen -. eine, die nie erklärt wurde, so dass ihr Wert Null ist

Ich würde auch empfehlen bei Klassenvariablen suchen, die mit dem Präfix „@@“ - hier einige Beispiel-Code, den Sie zu zeigen, wie Klassen- und Instanz Vars unterschiedlich sind:

class Vars
  @@classvar="foo"
  def test
    @instancevar="bar"
  end
  def Vars.show
    puts "classvar: #{@@classvar}"
    puts "instancevar: #{@instancevar}"
  end
  def instance_show
    puts "classvar: #{@@classvar}"
    puts "instancevar: #{@instancevar}"

  end
end

# only shows classvar since we don't have an instance created
Vars::show
# create a class instance
vars = Vars.new
# instancevar still doesn't show b/c it hasn't been initialized
vars.instance_show
# initialize instancevar
vars.test
# now instancevar shows up as we expect
vars.instance_show
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top