2010-02-17 2 views
5

Я работал на том, чтобы лучше понять Руби и вот что-то у меня возникают проблемы с:установки глобальной в процедурный

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

Приведенный выше код частично взят из источника Эрба переписан, чтобы лучше выделить пример. В основном внутри proc можно установить значение $SAFE независимо от того, что нужно и после proc, значение SAFE возвращается к тому, что было до proc.

Если вместо того, чтобы использовать слово $SAFE я изменить его на другое слово, например, $DOOR:

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

то значение $DOOR после прока является 2, а не 1. Почему разница между этими двумя Примеры?

ответ

11

Это довольно просто, на самом деле: причина, почему $SAFE не ведет себя так, как вы ожидали бы от глобальной переменной, потому что она не является глобальной переменной. Это волшебный единорог.

В Ruby существует немало таких магических единорогов, и, к сожалению, они не очень хорошо документированы (на самом деле не зафиксированы), поскольку разработчики альтернативных реализаций Ruby обнаружили трудный путь. Эти вещи все ведут себя по-разному и (по-видимому) непоследовательно, и в значительной степени единственные две вещи, которые у них есть, - это то, что они выглядят как глобальные переменные, но не ведут себя как они.

Некоторые из них имеют местный охват. Некоторые из них имеют локальную область. Некоторые магически меняются, если никто не назначает их. Некоторые имеют магический смысл для переводчика и изменяют поведение языка. У некоторых есть другая странная семантика, привязанная к ним.

$SAFE имеет почти все вышесказанное: это нить-локальный, что означает, что если вы меняете его в одном потоке, это не влияет на другие потоки. Это локально, то есть если вы меняете его в локальной области (например, класс, модуль, метод или блок), это не влияет на внешнюю область (как вы обнаружили).Он имеет магическое значение для интерпретатора, поскольку установка его значения, отличного от 0, делает определенные вещи неработоспособными. И у этого есть дополнительная странная семантика, в которой вы можете только увеличить его значение, никогда уменьшение it.

+0

ОК, это именно то, что я хотел знать. Я смотрел и надеялся на последовательность, но вместо этого я обнаружил, что мы имеем дело с волшебным единорогом. :-) – Francois

3

Я не знаю точно, почему $ SAFE работает именно так, но я знаю, что это предопределенная глобальная переменная с магическим значением, связанным с испорченными внешними данными и потоками.

Поэтому не используйте его как программный объект.

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

Это не так, кстати, должна быть обеспечена возможность снизить стоимость $ SAFE с заданием, но он прикреплен к контексту выполнения и многопоточной программы, например, может иметь несколько $ SAFE в разных потоках ...

+0

Я прочитал информацию о taint, и я вижу, что $ SAFE является предопределенной глобальной переменной. Но я не совсем понимаю, почему предопределенные глобальные вары ведут себя иначе, чем другие глобальные вары. – Francois

+1

Причина варьируется в зависимости от переменной, в случае $ SAFE это потому, что все дело в том, чтобы сделать одностороннюю эскалацию паранойи. Если $ SAFE может уменьшаться посредством назначения, вложенный код может просто включать присвоение $ SAFE. – DigitalRoss

1

Значение $DOOR должно быть 2. поскольку глобальная переменная $DOOR была повторно инициализирована с 1 на 2. Подробнее о Global Variables.

$SAFE безопасные уровни путем установки переменной $SAFE. По умолчанию значение установлено на ноль.

и $SAFE в прок будет там в памяти до конца объема .Hence это отображение проверки ранее установленное значение т.е. 1. Более подробно об этом here, а также docs

Смежные вопросы