Блок Ruby, procs и instance_eval
Недавно я попытался сделать что-то похожее на это:
a = "some string"
b = Proc.new{ upcase }
a.instance_eval b
Который дает ошибку:
TypeError: невозможно преобразовать Proc в строку
но это работает:
def b(&block)
"some string".instance_eval &block
end
b{ upcase }
Дальше посмотрите с помощью этого метода:
def b(&block)
"some string".instance_eval block
end
Устанавливает ту же ошибку Proc to String
.
Итак... мое понимание блоков состоит в том, что они просто проки. Но, очевидно, что-то особенное в том, что этот амперсанд &
...
Может кто-нибудь объяснить это мне? Возможно ли преобразовать обычный proc в то, что является особенным в этом объекте &block
?
изменить
Только что выяснил мой второй вопрос, добавьте &
в proc... это было легко, но ЧТО это действительно делает?
Ответы
Ответ 1
Все, что вам нужно сделать для первого примера работы:
>> a.instance_eval &b #=> "SOME STRING"
Причина в том, что instance_eval
требуется либо строка, либо блок, и амперсанд предоставляет последнюю.
Для понимания различий между блоками и procs, возможно, следующее сообщение в блоге помогает:
Понимание блоков Ruby, Procs и Lambdas
Ответ 2
Отличие состоит в том, что a.instance_eval b передает b как обычный аргумент instance_eval, тогда как a.instance_eval & b передавая его как блок. Это две разные вещи.
Рассмотрим этот вызов метода:
obj.foo(bar) do | x | stuff (x) end
Это вызывает метод foo с одним регулярным аргументом (bar) и одним блочным аргументом ( do | x | stuff (x) end). В определении метода они отличаются префиксом & к параметру блока:
def foo (arg, & block)
...
конец
И если вы хотите передать переменное выражение вместо литерального блока, то это также выполняется путем префикса и выражения (которое должно давать Proc).
Если вы передаете аргумент без &, он переходит в слот arg вместо слота блока. Не имеет значения, что аргумент оказывается экземпляром Proc. Синтаксис определяет, как он передается и обрабатывается методом.
Ответ 3
Это потому, что instance_eval принимает строку для eval или block. instance_eval(&block)
передает ваш block
в качестве блока instance_eval.
Ответ 4
Важнейшим отличием является то, что экземпляр Proc является объектом, тогда как блок не является объектом. &
- это оператор, который взаимно заменяет блок и экземпляр Proc.
Все аргументы метода должны быть объектом. В дополнение к аргументам, метод может принимать блок. instance_eval
- это метод, который принимает либо аргумент String, либо блок. Передача объекта Proc не будет удовлетворять ни одному случаю. Если вы присоедините &
к объекту Proc, это будет обработано как блок.
Ответ 5
Это будет работать:
a = "some string"
b = Proc.new{ upcase }
a.instance_eval &b
Метод instance_eval
может принимать блок-аргументы.
b
является Proc
.