Ruft den Wert einer Instanzvariablen ab, deren Name angegeben ist

99

Wie kann ich im Allgemeinen einen Verweis auf ein Objekt erhalten, dessen Name ich in einer Zeichenfolge habe?

Insbesondere habe ich eine Liste der Parameternamen (die Mitgliedsvariablen - dynamisch erstellt, sodass ich nicht direkt auf sie verweisen kann).

Jeder Parameter ist ein Objekt, das auch eine from_sMethode hat.

Ich möchte so etwas wie das Folgende machen (was natürlich nicht funktioniert ...):

define_method(:from_s) do | arg |
    @ordered_parameter_names.each do | param |
        instance_eval "field_ref = @#{param}"
        field_ref.from_s(param)
    end
end
LK__
quelle

Antworten:

178

Der idiomatischste Weg, dies zu erreichen, ist:

some_object.instance_variable_get("@#{name}")

Es besteht keine Notwendigkeit, +oder zu verwenden intern; Ruby wird das gut machen. Wenn Sie jedoch feststellen, dass Sie in ein anderes Objekt greifen und dessen Ivar herausziehen, besteht eine recht gute Chance, dass Sie die Kapselung gebrochen haben.

Wenn Sie explizit auf ein ivar zugreifen möchten, müssen Sie es zu einem Accessor machen. Folgendes berücksichtigen:

class Computer
  def new(cpus)
    @cpus = cpus
  end
end

In diesem Fall wären Sie Computer.newgezwungen, zu verwenden instance_variable_get, um zu gelangen @cpus. Aber wenn Sie dies tun, wollen Sie wahrscheinlich @cpusöffentlich sein. Was Sie tun sollten, ist:

class Computer
  attr_reader :cpus
end

Jetzt können Sie tun Computer.new(4).cpus.

Beachten Sie, dass Sie jede vorhandene Klasse erneut öffnen und aus einem privaten Ivar einen Reader machen können. Da ein Accessor nur eine Methode ist, können Sie dies tunComputer.new(4).send(var_that_evaluates_to_cpus)

Yehuda Katz
quelle
Gibt instance_variable_get ("@ # {name}") nicht den Wert der Variablen zurück? Ich brauche einen Verweis auf das eigentliche Objekt. Am Ende habe ich neu geschrieben. Anstatt viele Variablen + ein Array mit den Namen in der gewünschten Reihenfolge zu haben, habe ich die Parameter selbst in das Array eingefügt (die Entwurfsentscheidung war, ob jedes Mal auf Variablen zugegriffen werden soll, indem das Array durchsucht wird, oder ob durch Optimieren mit einem optimiert wird zusätzliches Array mit ihren Namen, die nur bei Bedarf verwendet werden)
LK__
Nein: instance_variable_get ("@ # {name}") gibt das tatsächliche Objekt zurück.
Yehuda Katz
Decken Sie den toten Faden für ein wenig Klarheit auf. Das vollständige Beispiel wäre: Klasse Computer attr_read: cpus def new (cpus) @cpus = cpus end end?
Nicolas de Fontenay
"Wenn Sie jedoch feststellen, dass Sie in ein anderes Objekt greifen und dessen Ivar herausziehen, besteht eine recht gute Chance, dass Sie die Kapselung gebrochen haben." Wie brechen wir in den Ivar eines anderen Objekts ein?
RubyMiner
9

So erhalten Sie eine Instanzvariable aus dem Namen einer Instanzvariablen:

name = "paramName"
instance_variable_get(("@" + name).intern)

Dies gibt den Wert der Instanzvariablen zurück @paramName

Daniel Lucraft
quelle
Beim dynamischen Erstellen einer Klasse habe ich ein Array mit Instanzvariablennamen (ich benötige diese Liste, da ich sie in einer bestimmten Reihenfolge behandeln muss). Mit diesem Namen möchte ich einen Verweis auf die Variable erhalten.
LK__
1
Ich habe eine Zeichenfolge "paramName" und benötige einen Verweis auf @paramName
LK__
1
OK. Ich empfehle Ihnen, Ihre Frage zu bearbeiten, um genau diese beiden Kommentare zu sagen.
Daniel Lucraft
2
Dies hat auch nichts mit Deserialisierung zu tun. Ein besserer Titel könnte "Den Wert einer Instanzvariablen anhand ihres Namens abrufen" oder so sein.
Daniel Lucraft
Sie können jederzeit ein Modul erstellen und hinzufügen, :attr_reader varnameum dann sauberer und weniger ausführlich auf die Variablen zuzugreifen.
ocodo