установка глобального в рамках процесса - PullRequest
6 голосов
/ 17 февраля 2010

Я работаю над тем, чтобы лучше понять Ruby, и вот что у меня проблемы:

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

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

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

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

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

Ответы [ 3 ]

11 голосов
/ 17 февраля 2010

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

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

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

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

3 голосов
/ 17 февраля 2010

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

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

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

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

1 голос
/ 17 февраля 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...