首页 文章

何时以及如何使用`each`方法?

提问于
浏览
0

我不明白为什么在这段代码中定义 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 . 另外,如果我使用 ArrayRange 类,并在其中覆盖 each 方法,则会发生不同的事情 .

当我创建一个对象,并在其上调用 inject 方法时, each 方法何时以及如何工作?

1 回答

  • 1

    TL:DR Enumerable mixin和你签订了一份 Contract . 你告诉它 each 的意思,它带来了几十种额外的方法 . inject 是其中一种方法 .

    实际讨论

    inject 如何运作?粗略地说,它遍历由元素组成的东西,在元素到达时将元素应用于元素 . 字符串 "the quick brown fox jumped" 的元素是什么?可以说,它们是它的角色 . 因此,如果我们将字符串视为一个字符数组并注入连接字符串的 + ,我们希望得到原始字符串本身:

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

    但现在让我们更进一步 . Ruby有mixins,特别是它有Enumerable mixin . 这允许我们将任何我们喜欢的东西视为"something that has elements" . 因此,不要使用数组,让我们可以在字符串本身的元素上注入 + . 为此,我们必须为String定义 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 别名化为 each_char . 我们已经知道了一种方法,使用 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
    

    但是,通过以这种奇怪的方式定义 each ,我们不要蹩脚 . 让's sluff this whole functionality off onto a custom class. Let'称它为VowelFinder!因此,我们最终得到了您开始使用的代码 .

相关问题