2010-02-17 7 views
5

He estado trabajando en tratar de comprender mejor Ruby y aquí es algo que estoy teniendo problemas con:el establecimiento de un mundial dentro de un proc

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

El código anterior es tomada en parte de la fuente de Erb reescrito para resaltar mejor el ejemplo. Básicamente dentro del proceso se puede establecer el valor de $SAFE en cualquier valor que se quiera y, después del proceso, el valor de SAFE vuelve a ser lo que era antes del proceso.

Si en lugar de utilizar la palabra $SAFE lo cambio a una palabra diferente, como $DOOR:

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

entonces el valor de $DOOR después de que el proc es 2 y no 1. ¿Por qué la diferencia entre los dos ejemplos?

Respuesta

11

Es bastante simple, en realidad: La razón por la cual $SAFE no se comporta como se esperaría de una variable global es porque no es una variable global. Es una magia mágica del unicornio.

Hay bastantes de esas maravillas mágicas del unicornio en Ruby, y desafortunadamente no están muy bien documentadas (de hecho, no están documentadas), ya que los desarrolladores de las implementaciones alternativas de Ruby se enteraron por las malas. Todas estas cosas se comportan de manera diferente y (aparentemente) inconsistente, y prácticamente las dos únicas cosas que tienen en común es que se ven como variables globales pero no se comportan como ellas.

Algunos tienen alcance local. Algunos tienen alcance local de subprocesos. Algunos cambian mágicamente sin que nadie los asigne. Algunos tienen un significado mágico para el intérprete y cambian el comportamiento del lenguaje. Algunos tienen otra semántica extraña unida a ellos.

$SAFE tiene casi todo lo anterior: es thread-local, lo que significa que si lo cambia en un hilo, no afecta a otros hilos. Es local, lo que significa que si lo cambia en un ámbito local (como una clase, módulo, método o bloque), no afecta el ámbito externo (como ha descubierto).Tiene un significado mágico para el intérprete, ya que establecerlo en un valor diferente de 0 hace que ciertas cosas no funcionen. Y tiene una semántica extraña adicional en la que solo puede aumentar su valor, nunca disminuir.

+0

bien, eso es exactamente lo que quería saber. Estaba buscando y esperando coherencia, pero aquí en cambio me parece que estamos lidiando con una magia mágica del unicornio. :-) – Francois

3

No sé exactamente por qué $ SAFE funciona de esa manera, pero sí sé que es una variable global predefinida con un significado mágico relacionado con los datos y los hilos externos corruptos.

Así que no lo use como un objeto de programa.

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

No es, por cierto, supone que es posible bajar el valor de $ seguro con una misión, pero se une al contexto de ejecución y un programa de multiproceso, por ejemplo, puede tener múltiples $ Valores SEGUROS en diferentes hilos ...

+0

He leído sobre las cosas de la corrupción y veo que $ SAFE es una variable global predefinida. Pero no entiendo por qué los vars globales predefinidos se comportan de manera diferente a otros vars globales. – Francois

+1

La razón varía según la variable, en el caso de $ SAFE es porque todo el asunto es hacer una escalada de paranoia en un solo sentido. Si $ SAFE pudiera disminuir por asignación, el código inyectado podría simplemente incluir una asignación a $ SAFE. – DigitalRoss

1

El valor de $DOOR debe ser 2. porque la variable global $DOOR se ha reinicializado de 1 a 2. Más detalles en Global Variables.

$SAFE niveles de seguridad configurando la variable $SAFE. Por defecto es establecido en cero.

y $SAFE dentro del proc habrá un no en la memoria hasta el final del alcance .Hence es mostrar el valor previamente establecido es decir 1. comprobación más en este here y también docs

Cuestiones relacionadas