Может кто-нибудь объяснить, как выполняется следующий код? - PullRequest
0 голосов
/ 04 марта 2020

Я следую связанному учебнику из проекта Odin, о блоках и процессах в ruby. Я не совсем понимаю, как работает следующий код.

class Array
  def eachEven(&wasABlock_nowAProc)
    # We start with "true" because arrays start with 0, which is even.
    isEven = true

    self.each do |object|
      if isEven
        wasABlock_nowAProc.call object
      end

      isEven = (not isEven)  # Toggle from even to odd, or odd to even.
    end
  end
end

['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
  puts 'Yum!  I just love '+fruit+' pies, don\'t you?'
end

# Remember, we are getting the even-numbered elements
# of the array, all of which happen to be odd numbers,
# just because I like to cause problems like that.
[1, 2, 3, 4, 5].eachEven do |oddBall|
  puts oddBall.to_s+' is NOT an even number!'
end

Является ли ['apple', 'bad apple', 'cherry', 'durian'] блоком в этом контексте, и мы вызываем метод isEven для этого блока?

Использует ли isEven только значение true или false, и если true, будет выполнен следующий код?

do |fruit|
  puts 'Yum!  I just love '+fruit+' pies, don\'t you?'
end

Кроме того, что делает эта строка?

self.each do |object|
 if isEven
   wasABlock_nowAProc.call object
 end
end

Если isEven равен true, тогда вызвать [1, 2, 3, 4, 5] с объектом ??? Что означает вызов этого блока с object?

Ответы [ 2 ]

2 голосов
/ 05 марта 2020

Давайте сделаем это по частям:

1) Класс Array был родным от ruby, что означает, что мы добавляем метод ко всем экземплярам Array, метод - eachEven.

2) Этот метод получает в качестве параметра блок для выполнения, помните об этой информации.

3) ["apple", "bad apple", "cherry"] это экземпляр из Array, что означает, что мы можем выполнить метод eachEven для этого массива:

array = ["apple", "bad apple", "cherry"]
array.eachEven do |something| 
# The do/end block is the parameter passed to the method `eachEven` 
# the block will be binded in `wasABlock_nowAProc` in this case
end

4) Внутри метода eachEven мы получаем self (self - это сам массив) и выполнить другой метод из экземпляра Array: each (этот метод выполняет итерацию по массиву, привязывая текущую позицию к переменной внутри скобок: | object |)

5) Если условие возвращается положительный результат, он выполнит блок внутри, если, в случае:

wasABlock_nowAProc.call object
# We execute the block of step 2 passing the current position value as a parameter

Фактически, если мы выполним следующий код:

array = [1, 2, 3, 4]
array.eachEven do |position_value| 
  puts "The #{position_value} is even"
end

Мы получим следующий результат :

The 1 is even # The block `wasABlock_nowAProc` will bind the 1 to the object and print it
The 3 is even # Same here, 3 will be used as the object in the execution of `wasABlock_nowAProc`

Надеюсь, это поможет

1 голос
/ 05 марта 2020

Давайте разберем здесь код:

['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
  puts 'Yum!  I just love '+fruit+' pies, don\'t you?'
end

То, что у нас здесь, сводится к:

receiver.method do |block_argument_one|
  # this is the _body_ of the _block_
end

Итак:

  • ['apple', 'bad apple', 'cherry', 'durian'] называется приемник (или субъект , или просто объект или экземпляр )
  • eachEven является метод , вызываемый на получателе
  • Все от do до end является блоком. Это также может быть от { до } и работать одинаково (ну, в основном )
  • |fruit| - список аргументов блока, с fruit - единственным аргументом блок заботится о.
  • puts … это тело блока

Что происходит с блоком:

  1. Код в блоке получает интерпретируется, но не запускается
  2. Заполнитель для этого кода передается методу, к которому прикреплен блок
  3. , метод выполняется и может получить доступ к блоку во время выполнения

Теперь давайте посмотрим, как работает метод, который принимает блок:

class SomeClass
  def some_method(regular_argument, &block_capture_argument)
    # method body

    # explicitly call the block:
    block_capture_argument.call("first value passed to block")

    # implicitly call the block (same as above)
    yield "first value passed to block"
  end
end

Здесь показано несколько способов использования блока:

Когда вы определяете метод с началом последнего аргумента с & ссылка на блок становится доступной для метода по имени после & (например, ваш аргумент wasABlock_nowAProc). Тогда ваш метод может делать то, что ему нравится, с блоком, может вызывать его или даже хранить его где-то, и совсем другой метод может использовать его.

В качестве альтернативы, вы можете использовать ключевое слово yield для вызова блока неявно. В этом случае вам не нужен аргумент & для метода (но он все еще работает, если у вас есть этот аргумент). Обратите внимание, что ruby позволяет вам присоединить блок к любому методу , независимо от того, использует ли он этот блок. Методы могут проверить, был ли блок с ключевым словом block_given?, или проверить, присутствует ли значение аргумента &.

Когда вы вызываете блок, либо с помощью yield, либо с call, аргументы, которые вы передаете методу вызова, передаются в качестве аргументов блоку.

Метод может сделать с блоком все, что он хочет . Он может вызывать его один, два, 0 или 300 раз. Он может вызывать его с одинаковыми аргументами каждый раз или с разными аргументами каждый раз.

В вашем конкретном примере c блок вызывается (со значением object) для каждого элемента в получателе , но только если переменная isEven имеет значение true.

Также в вашем конкретном примере c вы вызываете блок из другого блока (который предоставляет object для вас), но не позволяете этому сбить вас с толку.

Подводя итог:

  • блоков можно присоединить к любому методу с использованием либо do … end, либо {…}
  • блоков не запускаются, если только метод, к которому они присоединены, не решит вызвать их
  • методы будут вызваны на приемник
  • методы, использующие блоки get решить, как и когда их использовать
  • методы, которые используют блоки, могут вызывать блоки (или использовать yield) и передавать любое количество аргументов в блок. Блоки
  • могут быть определены для использования этих аргументов (с синтаксисом |…|) и могут именовать эти аргументы как угодно (важен порядок / позиция аргументов).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...