2010-02-17 4 views
5

ho lavorato per cercare di capire meglio Ruby e qui è qualcosa che sto avendo problemi con:l'impostazione di un globale all'interno di un proc

$SAFE = 1 
puts $SAFE # 1 
proc { 
    $SAFE = 2 
    puts $SAFE # 2 
}.call 
puts $SAFE # 1 

Il codice di cui sopra è parzialmente tratto da fonte di Erb riscritto per una migliore evidenziazione l'esempio. Fondamentalmente all'interno del proc è possibile impostare il valore di $SAFE a qualsiasi valore desiderato e dopo il proc, il valore di SAFE ritorna a ciò che era prima del proc.

Se invece di usare la parola $SAFE lo cambio ad una parola diversa, come ad esempio $DOOR:

$DOOR = 1 
puts $DOOR 
proc { 
    $DOOR = 2 
    puts $DOOR 
}.call 
puts $DOOR 

allora il valore del $DOOR dopo il proc è 2 e non 1. Perché la differenza tra i due esempi?

risposta

11

E 'piuttosto semplice, in realtà: il motivo per cui $SAFE non si comporta come ci si aspetterebbe da una variabile globale è perché non è una variabile globale. È un magico unicorno thingamajiggy.

Ci sono un bel po 'di cose magiche di unicorno in Ruby, e sfortunatamente non sono molto ben documentate (per niente documentate, infatti), come gli sviluppatori delle implementazioni alternative di Ruby hanno scoperto la via difficile. Questi thingamajiggies si comportano tutti in modo diverso e (apparentemente) incoerentemente, e praticamente le uniche due cose che hanno in comune è che assomigliano a variabili globali ma non si comportano come loro.

Alcuni hanno ambito locale. Alcuni hanno un ambito locale del thread. Alcuni cambiano magicamente senza che nessuno li assegni mai. Alcuni hanno un significato magico per l'interprete e cambiano il modo in cui si comporta la lingua. Alcuni hanno un'altra strana semantica collegata a loro.

$SAFE ha quasi tutto quanto sopra: è thread-local, il che significa che se lo si modifica in un thread, non ha alcun effetto sugli altri thread. È locale, il che significa che se lo si modifica in un ambito locale (come una classe, un modulo, un metodo o un blocco), non influisce sull'ambito esterno (come hai scoperto).Ha un significato magico per l'interprete, poiché impostarlo su un valore diverso da 0 rende certe cose non funzionanti. E ha semantica strana in quanto si può sempre solo aumentare il valore, mai diminuire it.

+0

ok, questo è esattamente quello che volevo sapere. Stavo guardando e sperando nella coerenza ma qui invece trovo che abbiamo a che fare con un magico unicorno thingamajiggy. :-) – Francois

3

Non so esattamente perché $ SAFE funzioni in questo modo, ma so che si tratta di una variabile globale predefinita con un significato magico correlato a dati e thread esterni contaminati.

Quindi non utilizzarlo come oggetto programma.

Vedi http://ruby-doc.org/docs/ProgrammingRuby/html/taint.html

Non è, a proposito, dovrebbe essere possibile abbassare il valore di $ SAFE con un incarico, ma è attaccato al contesto di esecuzione e un programma multithread, ad esempio, possono avere più $ Valori SICURI in diversi thread ...

+0

Ho letto le informazioni sulla contaminazione e vedo che $ SAFE è una variabile globale predefinita. Ma non capisco perché le vars globali predefinite si comportino diversamente dalle altre vars globali. – Francois

+1

La ragione varia in base alla variabile, nel caso di $ SAFE è perché l'intero punto è fare un'escalation unidirezionale della paranoia. Se $ SAFE potrebbe diminuire con l'assegnazione, il codice inserito potrebbe includere semplicemente un incarico a $ SAFE. – DigitalRoss

1

Il valore di $DOOR deve essere 2. perché la variabile globale $DOOR è stata reinizializzata da 1 a 2. Maggiori dettagli su Global Variables.

$SAFE livelli di sicurezza impostando la variabile $SAFE. Per impostazione predefinita è impostato su zero.

e $SAFE nell'ambito del proc sarà un lì in memoria fino alla fine del campo di applicazione .Hence è la visualizzazione del controllo precedentemente impostato valore cioè 1. di più su questo here e anche docs

Problemi correlati