не могу понять счетчик числа triagle - PullRequest
0 голосов
/ 04 декабря 2018

не может понять этот код, как он работает.

triangular_numbers = Enumerator.new do |yielder|
 number = 0
 count = 1
 loop do
    number += count
    count += 1
    yielder.yield number  
  end
 end
5.times { print triangular_numbers.next, " " }

не может понять, как yielder работает для этого блока.как его yield работает для number переменной.Как сделать цикл работает 5 раз.и как triangular_number.next работает впервые.

Ответы [ 4 ]

0 голосов
/ 04 декабря 2018

Я добавляю фрагмент кода к уже понятному объяснению:

my_enum = Enumerator.new do |whatever_name_for_the_yielder|
  n = 0
  loop do
    whatever_name_for_the_yielder.yield "Return this: #{n}"
    n += 1
  end
end

puts my_enum.next #=> Return this: 0
puts my_enum.next #=> Return this: 1
puts my_enum.next #=> Return this: 2

Когда вы предоставляете конец итерации, она останавливается с ошибкой:

my_enum2 = Enumerator.new do |whatever_name_for_the_yielder|
  2.times do |n|
    whatever_name_for_the_yielder.yield "Return this: #{n}"
  end
  puts "Outside the loop"
end

puts my_enum2.next #=> Return this: 0
puts my_enum2.next #=> Return this: 1
puts my_enum2.next #=> Outside the loop
#=> ERROR: .....in `next': iteration reached an end (StopIteration)
0 голосов
/ 04 декабря 2018

Перечислитель - это то, что вы можете назвать next и получить что-то обратно.yielder - это механизм, который возвращает что-то, когда вызывается next.Выполнение останавливается на yield до следующего вызова next.

Поддельные аналогии

Вы можете думать о enumerator как о билетеМашина , как когда вы стоите в очереди в правительственном офисе.Когда вы нажимаете кнопку (next), вы получаете тикет .Внутри автомата есть желоб , где выдается билет.Но билетный автомат не постоянно печатает билеты.Он ожидает нажатия кнопки до того, как распечатает следующий билет, и пропустит его через желоб.

В этом случае аналогичный код будет:

ticket_machine = Enumerator.new do |chute|
 ticket = 0
 loop do
    #print_ticket
    chute.yield ticket #waits here until you hit the button
    ticket += 1
  end
 end
5.times { print ticket_machine.next, " " } # gets 5 tickets

Пример кода в основномто же самое, но вместо того, чтобы выпускать билеты, это выпуск треугольных чисел. желоб - это yielder, через который пропускаются числа.

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

0 голосов
/ 04 декабря 2018

Я постараюсь объяснить, что он делает по крупицам, так что вы можете попытаться обернуть его вокруг.

Enumerator.new do |yielder|
end

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

Внутри его области вы устанавливаете некоторые локальные переменные (которые будут сохраняться при повторном использовании объекта):

 number = 0
 count = 1

А затем вы устанавливаете цикл, который увеличивает number на count и count с помощью 1, а затем вызовите yield для вашего аргумента, передав ему number в качестве аргумента.

loop do
  number += count
  count += 1
  yielder.yield number  
end

5.times повторяет блок, переданный ему 5 раз.Блок

-> { print triangular_numbers.next, " " }

вызывает print, который принимает n аргументов и объединяет части для формирования строки, но не добавляет символ новой строки.

Первый аргумент - наш перечислитель nextвзаимодействие (triangular_numbers.next), которое будет вычислять текущий номер и доходность вызова для Enumerator::Yielder, который неявно создан, обрабатывая элемент управления обратно к вызывающему Fiber вместе со всеми переданными ему аргументами.

(Все счетчики реализованы как «Волокна» в МРТ)

Так что вызов yielder.yield аналогичен вызову Fiber.yield и позволит циклу 5.times работать и возвращать number 1.

0 голосов
/ 04 декабря 2018

Enumerator::new принимает блок.Этот блок при запуске получает Enumerator::Yielder, который имеет метод #yield.

Когда вызывается Enumerator#next, блок выполняется до первого Enumerator::Yielder#yield.Там исполнение приостановлено;значение, данное yield, является значением, которое возвращает next.Когда вы снова вызываете next для того же Enumerator, выполнение возобновляется и продолжается до тех пор, пока снова не встретится yield.


Итак, в вашем случае 5.times выполняет свой блок,намереваясь повторить это пять раз.triangular_numbers.next называется;это запускает выполнение блока выше.number и count устанавливаются в свои значения, и запускается бесконечный цикл.number устанавливается на 1, count устанавливается на 2, а затем мы находим yielder.yield.Это приостанавливает выполнение блока и возвращает элемент управления туда, где next был вызван внутри цикла 5.times.next возвращает 1, потому что yielder.yield получил number (1).

Во второй раз через цикл 5.times мы хотим напечатать следующее число.Это останавливает основную строку выполнения и возобновляет блок перечисления сразу после yielder.yield.Бесконечный цикл продолжается;number is 3, count is 3, yielder.yield приостанавливает работу счетчика и возобновляет основной код.next получает 3, который печатается.

Третий, четвертый и пятый раз в цикле 5.times абсолютно одинаковы.

После пяти итераций цикл 5.times заканчиваетсяи исполнение продолжается мимо него.Перечислитель находится в режиме паузы и готов дать следующий номер по порядку, если вы когда-нибудь снова наберете next (так как он имеет бесконечный цикл), но вы этого не сделаете, и программа завершит работу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...