Frage

Ich bin nicht ganz sicher, ob dies in Ruby möglich ist, aber hoffentlich gibt es eine einfache Möglichkeit, dies zu tun. Ich möchte eine Variable deklarieren und später den Namen der Variablen erfahren. Das heißt, für diesen einfachen Code-Schnipsel:

foo = ["goo", "baz"]

Wie kann ich den Namen des Arrays erhalten (hier: „foo“) zurück? Wenn es tatsächlich möglich ist, funktioniert das auf jeder Variable (zum Beispiel Skalare, Hashes, etc.)?

Edit: Hier ist, was ich im Grunde zu tun versuchen. Ich schreibe einen SOAP-Server, der mit drei wichtigen Variablen um eine Klasse umschließt, und der Validierungscode ist im Wesentlichen so aus:

  [foo, goo, bar].each { |param|
      if param.class != Array
        puts "param_name wasn't an Array. It was a/an #{param.class}"
        return "Error: param_name wasn't an Array"
      end
      }

Meine Frage ist dann: Kann ich die Instanzen von ‚param_name‘ mit foo, Schmiere oder bar ersetzen? Diese Objekte sind alle Arrays, so dass die Antworten, die ich erhalten habe, so weit scheinen nicht zu arbeiten (mit Ausnahme von Re-Engineering, die ganze Sache ala dbr Antwort )

War es hilfreich?

Lösung

Was passiert, wenn Sie Ihr Problem umdrehen? Stattdessen Namen von Variablen zu erhalten, zu versuchen, die Variablen aus dem Namen bekommen:

["foo", "goo", "bar"].each { |param_name|
  param = eval(param_name)
  if param.class != Array
    puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
    return "Error: #{param_name} wasn't an Array"
  end
  }

Wenn es eine Chance auf einer der Variablen nicht definiert werden (im Gegensatz zu keinem Array ist), würden Sie wollen, „Rettung nil“ hinzufügen, um das Ende der „param = ...“ Zeile halten Sie die eval aus einer Ausnahme zu werfen ...

Andere Tipps

Sie müssen neu Architekt Ihre Lösung. Auch wenn Sie könnte es tun (man kann nicht), ist die Frage einfach keine vernünftige Antwort hat.

Stellen Sie sich eine get_name Methode.

a = 1
get_name(a)

Jeder konnte wahrscheinlich zustimmen, diese zurückgeben sollte 'a'

b = a
get_name(b)

Sollte es zurückgeben 'b' oder 'a', oder ein Array beide enthalten?

[b,a].each do |arg|
  get_name(arg)
end

Sollte es 'arg' zurückkehren, 'b' oder 'a'?

def do_stuff( arg )
  get_name(arg)
do
do_stuff(b)

Sollte es arg ', ‚b‘ oder ‚a‘, oder vielleicht das Array alle von ihnen zurückkehren? Auch wenn es ein Array tut zurückgeben, was würde der Auftrag sein und wie würde ich wissen, wie die Ergebnisse zu interpretieren?

Die Antwort auf alle Fragen oben ist: „Es hängt von der jeweiligen Sache, die ich zu der Zeit will.“ Ich bin mir nicht sicher, wie Sie dieses Problem für Ruby lösen könnten.

Es scheint, Sie versuchen, ein Problem zu lösen, die eine weit einfachere Lösung hat ..

Warum speichert nicht nur die Daten in einem Hash? Wenn Sie das tun ..

data_container = {'foo' => ['goo', 'baz']}

.. es ist dann ganz einfach, die 'foo' Namen zu erhalten.

Das heißt, Sie haben jeden Zusammenhang mit dem Problem nicht gegeben, so kann es einen Grund geben Sie dies nicht tun können ..

[Bearbeiten] Nach der Klärung sehe ich das Problem, aber ich glaube nicht, das ist das Problem .. Mit [foo, bar, bla], es ist gleichwertig wie ['content 1', 'content 2', 'etc'] sagen. Der tatsächlichen Variablen Name ist (oder besser gesagt, soll) völlig irrelevant. Wenn der Name der Variablen wichtig ist, das ist genau das, warum Hashes existiert.

Das Problem ist nicht mit Iterieren über [foo, bar] usw., es ist das grundlegende Problem mit, wie der SOAP-Server die Daten returing, und / oder wie Sie versuchen, es zu benutzen.

Die Lösung, die ich sagen würde, ist entweder die SOAP-Server Rückkehr Hashes zu machen, oder, da Sie wissen, dass es immer drei Elemente sein wird, kann man nicht etwas tun, wie ..

{"foo" => foo, "goo" => goo, "bar"=>bar}.each do |param_name, param|
      if param.class != Array
        puts "#{param_name} wasn't an Array. It was a/an #{param.class}"
        puts "Error: #{param_name} wasn't an Array"
      end
end

OK, es funktioniert in Instanzmethoden, auch, und, bezogen auf Ihre spezifische Anforderung (die, die Sie in den Kommentar setzen), könnten Sie dies tun:

local_variables.each do |var|
  puts var if (eval(var).class != Fixnum)
end

Just ersetzen Fixnum mit Ihrer spezifischen Typprüfung.

Ich weiß nicht, von irgendeiner Weise einen lokalen Variablennamen zu erhalten. Aber können Sie die instance_variables Methode verwenden, dies wird ein Array aller Instanzvariablennamen im Objekt.

Einfacher Aufruf:

object.instance_variables

oder

self.instance_variables

ein Array aller Instanz Variablennamen zu erhalten.

Aufbauend auf joshmsmoore , so etwas wie dies würde wahrscheinlich tun es:

# Returns the first instance variable whose value == x
# Returns nil if no name maps to the given value
def instance_variable_name_for(x)
  self.instance_variables.find do |var|
    x == self.instance_variable_get(var)
  end
end

Es gibt Kernel::local_variables, aber ich bin mir nicht sicher, dass dies für eine Methode des lokalen Vars arbeiten, und ich weiß nicht, dass Sie es in einer solchen Art und Weise manipulieren kann wie zu tun, was Sie acheive wollen.

Gute Frage. Ich verstehe Ihre Motivation. Lassen Sie mich mit der Feststellung beginnen, dass es bestimmte Arten von besonderen Objekten sind, dass unter bestimmten Umständen Kenntnis der Variablen haben, zu dem sie zugewiesen wurden. Diese speziellen Objekte sind zB. Module Fällen Class Instanzen und Struct Instanzen:

Dog = Class.new
Dog.name # Dog

Der Haken dabei ist, dass dies nur funktioniert, wenn die Variable, die Zuordnung zu dem ausgeführt wird, eine Konstante ist. (Wir alle wissen, dass Ruby Konstanten sind nichts anderes als emotional sensible Variablen.) Also:

x = Module.new # creating an anonymous module
x.name #=> nil # the module does not know that it has been assigned to x
Animal = x # but will notice once we assign it to a constant
x.name #=> "Animal"

Dieses Verhalten von Objekten sich dessen bewusst, auf die Variablen sie zugewiesen wurden, wird gemeinhin als Konstante Magie (weil es auf Konstanten beschränkt ist). Aber diese höchst wünschenswert Konstante Magie funktioniert nur für bestimmte Objekte:

Rover = Dog.new
Rover.name #=> raises NoMethodError

Zum Glück ich ein Juwel y_support/name_magic geschrieben haben, die sich um das für Sie übernimmt:

 # first, gem install y_support
require 'y_support/name_magic'

class Cat
  include NameMagic
end

Die Tatsache, dass dies funktioniert nur mit Konstanten (dh. Variablen mit einem Großbuchstaben beginnt) ist nicht so eine große Einschränkung. In der Tat, es gibt Ihnen die Freiheit zu nennen oder nicht Ihre Objekte nach Belieben zu nennen:

tmp = Cat.new # nameless kitty
tmp.name #=> nil
Josie = tmp # by assigning to a constant, we name the kitty Josie
tmp.name #=> :Josie

Leider wird dies nicht mit Array-Literalen arbeiten, weil sie ohne die Verwendung von #new Verfahren intern aufgebaut sind, auf dem NameMagic beruht. Deshalb, um zu erreichen, was Sie wollen, müssen Sie Array Unterklasse:

require 'y_support/name_magic'
class MyArr < Array
  include NameMagic
end

foo = MyArr.new ["goo", "baz"] # not named yet
foo.name #=> nil
Foo = foo # but assignment to a constant is noticed
foo.name #=> :Foo

# You can even list the instances
MyArr.instances #=> [["goo", "baz"]]
MyArr.instance_names #=> [:Foo]

# Get an instance by name:
MyArr.instance "Foo" #=> ["goo", "baz"]
MyArr.instance :Foo #=> ["goo", "baz"]

# Rename it:
Foo.name = "Quux"
Foo.name #=> :Quux

# Or forget the name again:
MyArr.forget :Quux
Foo.name #=> nil

# In addition, you can name the object upon creation even without assignment
u = MyArr.new [1, 2], name: :Pair
u.name #=> :Pair
v = MyArr.new [1, 2, 3], ɴ: :Trinity
v.name #=> :Trinity

erreicht ich die ständige Magie imitierenden Verhalten von alle Konstanten in allen Namensräumen gesucht des aktuellen Objektraum Rubin. Dies verschwendet einen Bruchteil einer Sekunde, aber da die Suche nur einmal durchgeführt wird, gibt es keine Leistungseinbuße, wenn das Objekt seinen Namen herausfindet. In Zukunft hat Ruby-Core-Team const_assigned Haken versprochen.

Sie können nicht, müssen Sie an das Zeichenbrett zurück gehen und Re-Engineering Ihre Lösung.

Foo ist nur ein Ort, um einen Zeiger auf die Daten zu halten. Die Daten haben keine Kenntnis von dem, was auf sie verweist. In Smalltalk-Systemen Sie die VM für alle Zeiger auf ein Objekt fragen könnte, aber das würde man nur das Objekt erhalten, das die foo Variable enthalten ist, foo selbst nicht. Es gibt keine wirkliche Möglichkeit, einen vaiable in Ruby zu verweisen. Wie durch eine Antwort erwähnt können Sie stil einen Tag in den Daten platzieren, verweist, wo es aus oder so kam, aber in der Regel, dass ist kein guter apporach der meisten Probleme. Sie können einen Hash verwenden, um die Werte in erster Linie zu erhalten, oder einen Hash verwenden, um Ihre Schleife übergeben, damit Sie das Argument Namen für Validierungszwecke wie in DBR Antwort wissen.

Die nächste Sache, eine wirkliche Antwort auf Sie Frage ist die Enumerable Methode each_with_index anstelle von jedem verwendet werden, so:

my_array = [foo, baz, bar]
my_array.each_with_index do |item, index|
  if item.class != Array
    puts "#{my_array[index]} wasn't an Array. It was a/an #{item.class}"
  end
end

Ich entfernte die return-Anweisung aus dem Block, den Sie jeder / each_with_index vorbei waren, weil es nichts zu bedeuten haben / hat. Jede und each_with_index beide Rück das Array, auf dem sie in Betrieb waren.

Es gibt auch etwas über Umfang in den Blöcken erwähnenswert, hier: Wenn Sie eine Variable außerhalb des Blocks definiert haben, wird es in ihm zur Verfügung stehen. Mit anderen Worten, Sie könnten zu foo, bar, beziehen und direkt in den Block baz. Die Umkehrung gilt nicht:. Variablen, die Sie zum ersten Mal innerhalb des Blockes erstellen nicht verfügbar außerhalb davon sein

Schließlich wird die do / end Syntax für mehrzeilige Blöcke bevorzugt, aber das ist einfach eine Frage des Stils, obwohl es in Ruby-Code eines neueren Datums universell ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top