2010-02-17 18 views
5

Pracuję na próby, aby lepiej zrozumieć, Ruby i tutaj coś mam problemy z:ustawienia globalne w proc

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

Powyższy kod jest częściowo wzięty ze źródła ERB jest przepisany w celu lepszego podkreślenia przykład. Zasadniczo w ramach proc można ustawić wartość $SAFE na dowolną wartość i po proc, wartość SAFE wraca do tego, co było przed proc.

Jeśli zamiast używania słowa $SAFE ją zmienić na inną propozycją, takich jak $DOOR:

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

wówczas wartość $DOOR po proc jest 2 a nie 1. Dlaczego różnica między dwoma przykłady?

Odpowiedz

11

To dość proste, naprawdę: powodem, dla którego $SAFE nie zachowuje się tak, jak można oczekiwać od zmiennej globalnej, jest to, że nie jest zmienną globalną. To magiczny jednorożec.

W Ruby jest sporo tych magicznych jednorożców, a niestety nie są one dobrze udokumentowane (w ogóle nie udokumentowane), ponieważ twórcy alternatywnych implementacji Rubiego odkryli trudną drogę. Wszystkie te rzeczy zachowują się różnie i (na pozór) niekonsekwentnie, a jedyne, co mają ze sobą wspólnego, to to, że wyglądają jak globalne zmienne, ale nie zachowują się tak jak oni.

Niektóre mają zasięg lokalny. Niektóre mają zasięg lokalny wątku. Niektóre zmieniają się w magiczny sposób, bez przypisywania im nikogo. Niektóre mają magiczne znaczenie dla tłumacza i zmieniają sposób zachowania języka. Niektóre mają inne dziwne semantyki z nimi związane.

ma prawie wszystkie powyższe cechy: jest to wątek-lokalny, co oznacza, że ​​jeśli zmienisz go w jeden wątek, nie wpłynie to na inne wątki. Jest lokalny, co oznacza, że ​​jeśli zmienisz go w zakresie lokalnym (jak klasa, moduł, metoda lub blok), nie ma to wpływu na zakres zewnętrzny (jak odkryłeś).Ma znaczenie magiczne dla tłumacza, ponieważ ustawienie go na wartość inną niż 0 sprawia, że ​​pewne rzeczy nie działają. I ma dodatkową dziwną semantykę, że można tylko zwiększyć jego wartość, nigdy nie jest to zmniejszone o.

+0

OK, dokładnie to, co chciałem wiedzieć. Patrzyłem i miałem nadzieję na konsekwencję, ale tutaj widzę, że mamy do czynienia z magiczną jednorożcem. :-) – Francois

3

Nie wiem dokładnie, dlaczego $ SAFE działa w ten sposób, ale wiem, że jest to predefiniowana zmienna globalna o magicznym znaczeniu związanym ze skażonymi zewnętrznymi danymi i wątkami.

Więc nie używaj go jako obiektu programu.

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

To nie jest, btw, powinno być możliwe, aby obniżyć wartość $ SAFE z cesją, ale jest dołączony do kontekstu wykonania i wielowątkowym programem, na przykład, może mieć wiele $ Wartości BEZPIECZNE w różnych wątkach ...

+0

Czytałem na temat skażonych rzeczy i widzę, że $ SAFE jest predefiniowaną zmienną globalną. Ale nie do końca rozumiem, dlaczego predefiniowane globalne wariacje zachowują się inaczej niż inne globalne wariacje. – Francois

+1

Przyczyna różni się w zależności od zmiennej, w przypadku $ BEZPIECZNEGO jest to, ponieważ cały punkt polega na jednokierunkowej eskalacji paranoi. Jeśli $ SAFE może zmniejszyć się poprzez przypisanie, wstrzyknięty kod może po prostu zawierać przypisanie do $ SAFE. – DigitalRoss

1

Wartość $DOOR musi wynosić 2. ponieważ zmienna globalna $DOOR została ponownie zainicjalizowana z 1 na 2. Więcej szczegółów na temat Global Variables.

$SAFE bezpieczne poziomy poprzez ustawienie zmiennej $SAFE. Domyślnie jest to ustawiona na zero.

i $SAFE w proc będzie tam w pamięci do końca zakresu .Hence jest wyświetlanie czek poprzednio ustawiona wartość czyli 1. więcej na ten temat here a także docs