2016-05-06 18 views
6

Perché il metodo non mostra @var_one rispetto alla variabile a?Variabili di istanza e classe Singleton

a = Object.new 

def a.my_eval; yield end 

a.my_eval { @var_one = 1 } 
a.instance_variables 
# => [] 
instance_variables 
# => [@var_one] 

risposta

9

Si dovrebbe usare instance_eval:

a.instance_eval { @var_one = 1 } 
=> 1 
a.instance_variables 
=> [:@var_one] 

Quando si utilizza ordinaria eval, si definisce il variabile di istanza nel contesto attuale self, se lo si fa in IRB, è l'oggetto main:

a.eval { self } 
=> main 

Quindi, è possibile modificare il metodo di a.eval eseguendo un blocco in un contesto di un'istanza:

def a.eval(&block) 
    instance_eval &block 
end 

a.eval { @a = 1 } 
=> 1 
a.instance_variables 
=> [:@a] 
2

Se il vostro obiettivo è quello di impostare una variabile di istanza a livello di codice, è possibile utilizzare:

a.instance_variable_set(:@var_one, 1) 
0

Si deve sapere la differenza tra eval e instance eval:

Kernel.eval valuta una stringa nella corrente contesto o il contesto del dato vincolo. È il metodo utilizzato da IRB per elaborare i tuoi input. Permette di definire nuove variabili e metodi per il contesto attuale.

Object.instance_eval valuta una stringa (o il blocco specificato) nel contesto di una certa istanza di classe e consente quindi l'accesso diretto alle proprietà della classe senza attr o attr_accessor. Permette di definire nuovi metodi per un'istanza.

Quindi:

a.instance_eval { @var_one = 1 } 
a.instance_variables 
# => [:@var_one] 
+1

@mhaseev definito la propria 'eval', quindi non utilizza' Kernel.eval'. Penso che la risposta sia più direttamente correlata al binding del blocco e al modo in cui 'yield' o' ProC# call 'interagiscono con quel binding. –

Problemi correlati