В Ruby, когда вы кладете yield
ключевое слово внутри любого метода (скажем #bar
), вы явно сообщая #bar
, что вы будете использовать блок с помощью метода #bar
. Таким образом, yield
знает, что внутри блока метода будет преобразован объект Proc
, и yield
должны называть это Proc
объектом.
Пример:
def bar
yield
end
p bar { "hello" } # "hello"
p bar # bar': no block given (yield) (LocalJumpError)
In the uniq_by
method, we did not do anything to handle block argument. How is the passed argument handled by uniq_by
method?
Вы действительно делали, что вы положили yield
. После того, как вы поместите этот yield
, теперь метод очень умный, чтобы знать, что это так. В строке Messages.all.uniq_by { |h| h.body }
вы передаете блок { |h| h.body }
, а внутри определения метода uniq_by
этот блок был преобразован в объект Proc
, а yield
- Proc#call
.
Доказательство:
def bar
p block_given? # true
yield
end
bar { "hello" } # "hello"
лучше для понимания:
class Array
def uniq_by
seen = Set.new
select{ |x| seen.add?(yield(x)) }
end
end
такой же, как
class Array
def uniq_by
seen = Set.new
# Below you are telling uniq_by, you will be using a block with it
# by using `yield`.
select{ |x| var = yield(x); seen.add?(var) }
end
end
Прочитайте документ о yield
Called from inside a method body, yields control to the code block (if any) supplied as part of the method call. If no code block has been supplied, calling yield
raises an exception. yield
can take an argument; any values thus yielded are bound to the block's parameters. The value of a call to yield
is the value of the executed code block.
'Array.uniq' занимает блок с [Ruby 1.9.3] (http://ruby-doc.org/core-1.9.3/Array.html#method-i-uniq), поэтому нет необходимости для этого кода (больше). – steenslag