Когда и как работает метод `each`? - PullRequest
0 голосов
/ 09 декабря 2018

Я не понимаю, почему метод each определен в этом коде:

class VowelFinder
  include Enumerable

  def initialize(string)
    @string = string
  end

  def each
    @string.scan(/[aeiou]/) do |vowel|
      yield vowel
    end
  end
end

vf = VowelFinder.new("the quick brown fox jumped")
vf.inject(:+)
# => "euiooue"

Этот код работает, но не без each.Кроме того, если я использую классы Array и Range и перезаписываю в них метод each, происходит что-то другое.

Когда я создаю объект и вызываю для него метод inject, когдаи как работает метод each?

1 Ответ

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

TL: DR Перечисляемый миксин работает по некоему контракту с вами.Вы говорите ему, что означает each, и это приносит в жизнь несколько десятков дополнительных методов.inject является одним из таких методов.

Актуальное обсуждение

Как работает inject?Грубо говоря, он проходит через нечто, состоящее из элементов , применяя функцию к элементам по мере их поступления.Каковы элементы строки "the quick brown fox jumped"?Возможно, они являются его персонажами.Поэтому, если мы будем рассматривать строку как массив символов и вставлять +, который объединяет строки, мы ожидаем получить саму оригинальную строку:

arr = "The quick brown fox jumped".scan /./
puts arr.inject(:+) # => the quick brown fox jumped

Но теперь давайте пойдем дальше.В Ruby есть миксины, и, в частности, есть Enumerable mixin.Это позволяет нам трактовать все, что нам нравится , как «что-то, что имеет элементы».Итак, вместо массива, давайте сделаем возможным вставлять + в элементы самой строки .Для этого мы должны определить each для строки, чтобы можно было ходить по элементам строки.Как только мы это сделаем, многие методы Enumerable, в том числе inject, оживут.

Что должен означать each для строки?Опять же, мы можем просто сделать так, чтобы это означало каждый персонаж.Мы могли бы сделать это путем наложения псевдонима each на существующий each_char:

class String
  include Enumerable
  alias each each_char
end
s = "the quick brown fox jumped"
puts s.inject(:+) # => the quick brown fox jumped

Но вместо наложения псевдонима each на each_char мы могли бы определить each сами с нуля.Мы уже знаем один способ сделать это, используя scan:

class String
  include Enumerable
  def each
    self.scan(/./) do |ch|
      yield ch
    end
  end
end
s = "the quick brown fox jumped"
puts s.inject(:+) # => the quick brown fox jumped

Но определение each зависит от меня, поэтому вместо сканирования на каждый символ яможет сканировать для некоторых другой шаблон!Например, я могу вместо этого искать гласные:

class String
  include Enumerable
  def each
    self.scan(/[aeiou]/) do |ch|
      yield ch
    end
  end
end
s = "the quick brown fox jumped"
puts s.inject(:+) # => euiooue

Но давайте не будем хромать String, определив each таким любопытным способом.Давайте перенесем всю эту функциональность на пользовательский класс.Давайте назовем это VowelFinder!Таким образом, мы получаем код, с которого вы начали.

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