Рубиновый блок, процы и 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
нужна либо строка, либо блок, а последний - амперсанд.
Для понимания различий между блоками и процессами, возможно, поможет следующее сообщение в блоге:
Разница в том, что 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
,