2012-11-14 12 views
13

Sagen, ich habe diesen Hash:Rubin wiederum Werte in einem Hash in lokale Variablen

entry = {"director"=>"Chris Nolan", "prducer"=>"Sum Duk", "writer"=>"Saad Bakk"} 

Ich mag jeden Schlüssel in seine eigenen lokalen Variable mit dem zugehörigen Wert extrahieren:

director = "Chris Nolan" 
producer = "Sum Duk" 
... 

Durch die Verwendung von eine Schleife und nicht:

director = entry["director"] 

Da gibt es viele Werte und ich möchte sie nicht einzeln machen.

Ich fand das fast perfekt funktioniert, außer es erstellt eine Instanzvariable und ich möchte eine lokale Variable, aber local_variable_set existiert aus irgendeinem Grund nicht.

entry.each_pair { |k, v| instance_variable_set("@#{k}", v) } 

Gibt es eine Lösung? Oder ist das nicht möglich, eine Instanzvariable in eine lokale Variable umzuwandeln und die Instanz zu löschen, ohne sie einzeln auszuführen?

+0

Gibt es Gründe, sie kann nicht im Hash bleiben und von dort aus zugegriffen werden? Vermutlich verwenden Sie die lokalen Variablen später - wäre es nicht genauso einfach, die Hashwerte zu verwenden? – Pavling

+0

Wenn Sie Rails (oder nur ActiveSupport) verwenden, können Sie den folgenden Einzeiler verwenden: 'director, producer, writer = entry.values_at ('director', 'producer', 'writer')'. Es ist bedauerlich, dass Sie jeden Variablennamen zweimal eingeben müssen (anstelle von null Mal, wie Sie es verlangten), aber es ist immer noch der prägnanteste Weg, den ich gefunden habe, um dies zu tun. – antinome

+0

mögliche Duplikate von [Wie dynamisch eine lokale Variable zu erstellen?] (Http://stackoverflow.com/questions/18552891/how-to-dynamically-create-a-local-variable) – Ajedi32

Antwort

2

Sie können aufgrund des Variablenbereichs keine lokalen Variablen erstellen.
Wenn Sie eine lokale Variable innerhalb eines Blocks erstellen, ist die Variable nur innerhalb des Blocks zugänglich.
Bitte beziehen Sie sich auf diese Frage für weitere Informationen.
Dynamically set local variables in Ruby

+0

Das macht Sinn, ist aber sehr traurig . Ich denke, ich bin stecken Instanzvariablen oder tun es manuell :( – kakubei

+0

In der Tat ist es. Ich denke, opfern einige Zeilen im Code ist der Weg zu gehen. – MurifoX

4

Sie können dies tun, mit eval, aber alle Operationen auf diesen Variablen innerhalb des Umfangs sein müssen sie in definiert wurden

Zum Beispiel wird diese Arbeit:.

vals = { 
    "foo" => "bar", 
    "baz" => "qux" 
} 

eval <<-EOF 
    #{ vals.map {|k, v| "#{k} = \"#{v}\""}.join("\n") } 
    puts foo 
EOF 

jedoch dies wird nicht:

vals = { 
    "foo" => "bar", 
    "baz" => "qux" 
} 

eval <<-EOF 
    #{ vals.map {|k, v| "#{k} = \"#{v}\""}.join("\n") } 
EOF 

puts foo 

als foo außerhalb des Gültigkeitsbereichs bei t geht er Ende der Eval. Wenn jedoch all Ihre Arbeit an den Variablen im Rahmen des Evals durchgeführt werden kann, ist dies durchaus machbar.

+0

@ kakubei: Genau, in Ruby können Sie fast jede Einschränkung durchbrechen. Obwohl die von Ihnen gewählte Variable - lokale Variablen - etwas schwierig ist, sind lokale Variablen nur für kleine Zeitbereiche gedacht .. –

+0

Das funktioniert nicht wirklich für Hashes mit nicht stringfähigen (oder stringbaren) Schlüsseln. – Hut8

2

Option 1

Ich kann das nicht, außer für Spaß empfehlen, aber es hat vor allem den Effekt, den Sie sind nach:

entry.each |k, v| 
    singleton_class.send(:attr_accessor, k) 
    send("#{k}=", v) 
end 

director      # => "Chris Nolan" 
self.director = "Wes Anderson" # Unfortunately, must use self for assignment 
director      # => "Wes Anderson" 

Stattdessen lokalen Variablen schafft es acccessor Methoden auf die definiert Singleton-Klasse des aktuellen Objekts, die Sie aufrufen können, als wären sie lokale Variablen.

Um sie "lokaler" zu machen, könnten Sie singleton_class.remove_method verwenden, um diese Methoden zu entfernen, wenn Sie damit fertig sind. Sie könnten sogar versuchen, alle vorhandenen Singleton-Klassenmethoden mit demselben Namen umzubenennen und sie anschließend wiederherzustellen.

Option 2

Dies ist etwas, was ich in echten Code verwenden. Es benötigt das ActiveSupport-Juwel, das mit Ruby On Rails geliefert wird, kann aber auch eigenständig verwendet werden.

Leider ist es erforderlich, jeden Variablennamen zweimal einzugeben, anstatt null mal, wie Sie gefragt haben. Wenn Sie über die Reihenfolge der Werte in der Hash sicher waren, könnten Sie schreiben:

director, producer, writer = entry.values # Not so good, IMO. 

ich über diese Version ein ungutes Gefühl, weil jetzt der Code, der den Hash erstellt eine nicht offensichtliche Verantwortung hat der Hash, um sicherzustellen, in einer bestimmten Reihenfolge.

Hinweis

Wenn Ihr Ziel ist einfach mit der Eingabe zu reduzieren, hier ist ein Ansatz, der nur zwei als mehr Zeichen pro Variable Zugriff erfordert, wenn sie echte lokale Variablen waren:

e = OpenStruct.new(entry) 
e.director  # => "Chris Nolan"