Ottieni il valore di una variabile di istanza dato il suo nome


99

In generale, come posso ottenere un riferimento a un oggetto il cui nome ho in una stringa?

Più specificamente, ho un elenco dei nomi dei parametri (le variabili membro - costruite dinamicamente, quindi non posso fare riferimento a loro direttamente).

Ogni parametro è un oggetto che ha anche un from_smetodo.

Voglio fare qualcosa come il seguente (che ovviamente non funziona ...):

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

Risposte:


179

Il modo più idiomatico per ottenere questo risultato è:

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

Non è necessario utilizzare +o intern; Ruby se la caverà bene. Tuttavia, se ti ritrovi a raggiungere un altro oggetto e ad estrarre il suo ivar, ci sono buone probabilità che tu abbia rotto l'incapsulamento.

Se vuoi esplicitamente accedere a un ivar, la cosa giusta da fare è renderlo un accesso. Considera quanto segue:

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

In questo caso, se lo facessi Computer.new, saresti costretto a usare instance_variable_getper arrivare a @cpus. Ma se lo fai, probabilmente intendi @cpusessere pubblico. Quello che dovresti fare è:

class Computer
  attr_reader :cpus
end

Adesso puoi farlo Computer.new(4).cpus.

Nota che puoi riaprire qualsiasi classe esistente e trasformare un ivar privato in un lettore. Poiché una funzione di accesso è solo un metodo, puoi farloComputer.new(4).send(var_that_evaluates_to_cpus)


Instance_variable_get ("@ # {name}") non restituisce il valore della variabile? Ho bisogno di un riferimento all'oggetto reale. Ho finito per riscrivere quindi, invece di avere molte variabili + un array con i nomi nell'ordine che volevo, ho inserito i parametri stessi nell'array (la decisione progettuale era se accedere alle variabili ogni volta cercando l'array o ottimizzare avendo un array aggiuntivo con i loro nomi che verrebbero utilizzati solo quando necessario)
LK__

No: instance_variable_get ("@ # {name}") restituisce l'oggetto effettivo.
Yehuda Katz

Scoprire il filo morto per un po 'di chiarezza. L'esempio completo sarebbe: class Computer attr_read: cpus def new (cpus) @cpus = cpus end end?
Nicolas de Fontenay

"Tuttavia, se ti ritrovi a toccare un altro oggetto ed estrarre il suo ivar, c'è una probabilità ragionevolmente buona che hai rotto l'incapsulamento.". Come entriamo nell'ivar di un altro oggetto?
RubyMiner

9

Per ottenere una variabile di istanza dal nome di una variabile di istanza:

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

Ciò restituirà il valore della variabile di istanza @paramName


Durante la creazione di una classe in modo dinamico, ho un array dei nomi delle variabili di istanza (ho bisogno di questo elenco perché ho bisogno di gestirli in un certo ordine). Utilizzando questo nome, voglio ottenere un riferimento alla variabile.
LK__

1
Ho una stringa "paramName" e ho bisogno di un riferimento a @paramName
LK__

1
OK. Ti consiglio di modificare la tua domanda per dire esattamente questi due commenti.
Daniel Lucraft

2
Inoltre, questo non ha nulla a che fare con la deserializzazione. Un titolo migliore potrebbe essere "Ottieni il valore di una variabile di istanza dato il suo nome" o qualcosa del genere.
Daniel Lucraft

Puoi sempre fare un modulo e aggiungere in :attr_reader varnamemodo da poter accedere alle variabili in modo più pulito e meno dettagliato.
ocodo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.