Рубиновый блок, процы и instance_eval

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

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

Который дает ошибку:

Ошибка типа: не удается преобразовать 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 объект?

редактировать

Просто разобрался со вторым вопросом & в процесс... это было легко, но что это на самом деле делает?

5 ответов

Решение

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

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

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

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

Понимание Ruby Blocks, Procs и Lambdas

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

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

obj.foo (bar) do | x | материал (х) конец

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

def foo (arg, & block)
...
конец

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

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

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

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

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

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

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

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

Другие вопросы по тегам