Разница между блок и и блок в Ruby


Почему иногда я должен использовать блок и другие времена и блок внутри функций, которые принимают блоки?

3 57

3 ответа:

block это просто локальная переменная, &block - это ссылка на блок, переданный в метод.

def foo(block = nil)
  p block
end

foo # => nil
foo("test") # => test
foo { puts "this block will not be called" } # => nil

def foo(&block)
  p block
end

foo # => nil
foo("test") # => ArgumentError: wrong number of arguments (1 for 0)
foo { puts "This block won't get called, but you'll se it referenced as a proc." }
# => #<Proc:0x0000000100124ea8@untitled:20>

вы также можете использовать &block при вызове методов для передачи proc как блока к методу, так что вы можете использовать procs так же, как вы используете блоки.

my_proc = proc {|i| i.upcase }

p ["foo", "bar", "baz"].map(&my_proc)
# => ["FOO", "BAR", "BAZ"]

p ["foo", "bar", "baz"].map(my_proc)
# => ArgumentError: wrong number of arguments (1 for 0)

в имя переменной block ничего особенного не значит. Вы можете использовать &strawberries если вам нравится, амперсанд является здесь ключевой.

вы можете найти в этой статье полезная.

в списке аргументов,&whatever берет блок, который был передан методу, и обертывает его в объект Proc. Proc хранится в переменной с именем whatever (где это может быть любое имя, которое вы ввели после амперсанда, конечно - обычно это "блок"). После вызова метода,&whatever синтаксис превращает Proc в блок. Поэтому, если вы определяете метод следующим образом:

def thing(&block)
  thing2 &block
end

вы определяете метод, который принимает блок, а затем вызывает другой метод с этим блоком.

если вы не установите блок & before, Ruby не распознает его отношение к "блоку", который вы передаете функции. Вот несколько примеров.

def f(x, block); end
f(3) { 2+2 }    # gives an error, because "block" is a
                # regular second argument (which is missing)

def g(x, &block); end
g(3) { 2+2 }    # legal

def h(x); end
h(3) { 2+2 }    # legal

для последующего использования в функции:

def x(&block)   # x is a 0 param function
  y(block)      # y is a 1 param function (taking one "Proc")
  z(&block)     # z is a 0 param function (like x) with the block x received
end

Итак, если вы называете z(&block) это (почти!!) то же самое, что и вызов z { yield }: вы просто передаете блок в следующую функцию.