2016-02-09 2 views
-1

Почему этот маленький фрагмент кода Ruby не работает?Tricky Ruby scoping issue

cached = {} 
def cache(*key) 
    cached[key.join] ||= yield 
end 
cache("key") do "value" end 

Я получаю следующее сообщение об ошибке:

NameError: undefined local variable or method `cached' for main:Object

Любые идеи?

ответ

3

Используйте переменную экземпляра вместо локального:

@cached = {} 
def cache(*key) 
    @cached[key.join] ||= yield 
end 

Вы не можете использовать локальную cached переменную внутри метода кэша, так как локальные переменные не существуют вне определения метода, так что если вы вратаря определить локальную переменную в методе body или method params ранее, Ruby не может его найти. Подробнее об видимости переменных here.

+0

Haha, wow, brainfart ... Вы правы, спасибо! – Dave

+0

Вопрос в том, почему код не работает? а не как заставить его работать? – Nermin

+0

Приведено объяснение причины. – Ilya

1

Я постараюсь дополнить ответ @ProgNoob.

Если вы пришли из таких языков, как C или C++, где область видимости создается с использованием блока кода.

{ 
    .... 
} 

И все локальные переменные внутри этой сферы не видны снаружи, но они видны в каждой области, созданной внутри, например:

{ 
    int a = 3; 
    { 
    // a is visible inside here 
    } 
    // a is visible inside here 
    ... 
} 
// a is not visible outside the scope 

Рубин не обрабатывает вещи одинаково. Когда вы создаете class, module или method, вы создаете совершенно новую область, не получая ничего из верхних областей, как мы видели в C.

v0 = 0 
class SomeClass # Scope gate 
    v1 = 1  
    # only v1 is visible here 

    def some_method # Scope gate 
    v2 = 2 
    # only v2 is visible here   
    end # end of def scope gate 
end # end of class scope gate 

Чтобы разорвать область применения ворот:

  • определения классов с с Class.new
  • определения модуля с Module.new
  • определений методов с define_method

Предыдущий пример без области видимости ворот

v0 = 0 
SomeClass = Class.new do 
    v1 = 1 
    # v0 and v1 visible here 

    define_method(:some_method) do 
    v2 = 2 
    # v0, v1 and v2 visible here 
    end 
end 
# v0 only visible here 
+0

Спасибо за подробное объяснение. Моя проблема заключалась в том, что я использовал переменную внутри блока, например 'foo = {}; что делать (здесь я использую foo) end', но позже, когда я попытался использовать его внутри метода, он не был определен. Теперь я вижу свою ошибку. – Dave