Как сделать блочные локальные переменные по умолчанию в ruby ​​1.9? - PullRequest
3 голосов
/ 05 января 2010

Ruby 1.9 дает возможность определять переменные, которые являются локальными для блока и не закрываются по переменным с тем же именем во внешней области видимости:

x = 10
proc { |;x|
    x = 20
}.call
x #=> 10

Я бы хотел использовать это поведение по умолчанию для некоторых блоков, которые я определяю - без необходимости использовать |; x, y, z | синтаксис (обратите внимание на точку с запятой).

Я не думаю, что Ruby позволяет это изначально, но возможно ли взломать эту функцию?

В настоящее время у меня есть одно решение, но оно довольно уродливо, так как требует проверки, какие локальные объекты изменились в конце блока, а затем возвращает их к их значениям до блока. Я не против, если ваше решение требует указать, какие переменные являются локальными в начале блока, т.е. scope(:x) { x = 20 }

Ответы [ 2 ]

7 голосов
/ 06 января 2010

Решение, которое я выбираю, основано на идее bobbywilson0. Вот как это работает:

x = 99
y = 98

scope { |x, y|
    x = 20
    y = 30
}

x #=> 99
y #=> 98 

Это полезно, так как переменные, используемые в scope, создаются в начале области действия и не закрываются по каким-либо переменным, определенным вне ее, они также GC'd в конце области.

Вот реализация:

def scope(&block)
    num_required = block.arity >= 0 ? block.arity : ~block.arity
    yield *([nil] * num_required)
end

Это решение также учитывает значения по умолчанию, делая его функционально эквивалентным let* в lisp.

scope { |x = 20, z = (x * 3)| 
    x #=> 20
    z #=> 60
}

Я написал об этом здесь: http://banisterfiend.wordpress.com/2010/01/07/controlling-object-scope-in-ruby-1-9/

4 голосов
/ 05 января 2010

x = 10; proc{ |x| x = 20 }.call(0)

...