2014-02-10 3 views
3

Я изучаю рубин в данный момент. Я пытаюсь понять, как работают замыкания, и как они отличаются от функций. Я полностью отдаю себе отчет в том, что замыкания должны быть реализованы через proc или лямбда.Понимание вложенных функций Ruby

Я пытаюсь получить глубокое понимание рубина. Таким образом, я проверяю все виды неортодоксального кода. Я пытаюсь понять, почему строка 3 работает, а строка 5 - ошибка.

x=123 
def b(x) 
    p x 
    def a(u) 
     p x # why is this an error?!?!? 
    end 
    a 4 
end 

b 1 
  1. Если не может получить доступ к параметрам Б, почему она не получить доступ к глобальной х = 123?
  2. Почему это работает, если я явно использую строки изменения 1 & 5 глобальному «$ x»?
  3. Почему это работает, если я использую лямбду явно?

Это чисто учебное упражнение, я делаю это, чтобы понять, что происходит под капотом.

ответ

4

Это что-то называется «рамкой». В принципе, когда вы начинаете определение метода/класса/модуля, создается новая область и не могут быть доступны все локальные переменные из других областей. Это не относится к экземпляру/глобальным переменным, вы будете иметь доступ к ним.

Поскольку лямбда-это не метод, он не создает новую область и не использует повторно существующую.

Кроме того,

почему линия 3 работает

x = 123 
def b(x) 
    p x # this "x" is "x the parameter", not "x the local variable from outer scope" 
     # that's why it works. If you tried to access the local var, it wouldn't work. 
    def a(u) 
     p x # like here, see? Doesn't work. 
    end 
    a 4 
end 

b 1 
3

Первое, что нужно понять, что def не делает "функцию" (что это вообще значит в Ruby?) - def определяет метод на каком-либо объекте или классе. Даже если он не находится внутри какого-либо объекта, он все же определяет метод на «основном» объекте. Поэтому, когда вы делаете def a, он не является «локальным» для метода b; это метод a так же, как если бы вы определили его на верхнем уровне, за исключением того, что он не определяется до b. Его можно назвать методом a из других мест. У вас есть определения вложенных методов.

Поскольку она должна была определить методы, которые большая часть времени определяются на верхнем уровне класса или модуль, def не был сделан, чтобы захватить внешние переменные.

+0

Из любопытства, что произойдет, если b - метод, принадлежащий классу? будет также принадлежать этому классу? – eshalev

+0

@eshalev: да. (но 'a' будет определяться только после запуска' b' в первый раз (для определения метода необходимо выполнить оператор 'def')) – newacct

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