Ruby block, procs и instance_eval - PullRequest
       39

Ruby block, procs и instance_eval

13 голосов
/ 16 июня 2011

Я недавно пытался сделать что-то похожее на это:

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.

Итак ... я понимаю, что блоки - это просто проки. Но очевидно, что в этом & амперсанде ...

есть что-то особенное

Может кто-нибудь объяснить мне это? Можно ли преобразовать обычный процесс в то, что является особенным в этом &block объекте?

1025 * редактировать * Просто разобрался со вторым вопросом, добавив & к процессу ... это было легко, но ЧТО это действительно делает?

Ответы [ 5 ]

22 голосов
/ 16 июня 2011

Все, что вам нужно сделать, чтобы ваш первый пример работал, это:

>> a.instance_eval &b #=> "SOME STRING"

Причина в том, что instance_eval нужна либо строка, либо блок, а амперсанд предоставляет последний.

Для понимания различий между блоками и процессами, возможно, поможет следующее сообщение в блоге:

Понимание блоков Ruby, процедур и лямбд

9 голосов
/ 17 июня 2011

Разница в том, что a.instance_eval b передает b в качестве обычного аргумента instance_eval, тогда как a.instance_eval & b передает его как блок,Это две разные вещи.

Рассмотрим вызов этого метода:

obj.foo (bar) do | x |stuff (x) end

, который вызывает метод foo с одним регулярным аргументом ( bar ) и одним аргументом блока ( do | x |материал (х) конец ).В определении метода они различаются префиксом & к параметру блока:

def foo (arg, & block)
...
end

И если вы хотите передать переменное выражение вместо литерального блока, это также достигается с помощью префикса & к выражению (что должно привести кProc).

Если вы передаете аргумент без & , он идет в слот arg вместо слота block .Неважно, что аргумент является экземпляром Proc.Синтаксис определяет, как он передается и обрабатывается методом.

1 голос
/ 16 июня 2011

Принципиальное отличие состоит в том, что экземпляр Proc является объектом , тогда как блок не является объектом . & - это оператор, который взаимозаменяет блок и экземпляр Proc взаимно.

Все аргументы метода должны быть объектом. В дополнение к аргументам метод может принимать блок. instance_eval - это метод, который принимает аргумент String или блок. Передача объекта Proc не удовлетворяет ни одному случаю. Если вы присоедините & к объекту Proc, он будет обработан как блок.

1 голос
/ 16 июня 2011

Это потому, что instance_eval принимает строку для eval или блок.instance_eval(&block) передает ваш block как блок в instance_eval.

0 голосов
/ 11 августа 2013

Это будет работать:

a = "some string"
b = Proc.new{ upcase }
a.instance_eval &b

Метод instance_eval может получать аргументы блока.b - это Proc.

...