我不明白为什么在此代码中定义了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
方法何时以及如何工作?
答案 0 :(得分:1)
TL:DR 可枚举的mixin与您签订了某种合同。您告诉它each
的含义,它带来了数十种其他方法。 inject
是这些方法之一。
inject
如何工作?粗略地说,它遍历了由 elements 组成的对象,并在元素到达时对其应用了功能。字符串"the quick brown fox jumped"
的元素是什么?可以说,它们就是它的角色。因此,如果我们将字符串视为字符数组并注入+
来连接字符串,那么我们期望得到原始的字符串本身:
arr = "The quick brown fox jumped".scan /./
puts arr.inject(:+) # => the quick brown fox jumped
但是现在让我们更进一步。 Ruby具有mixin,尤其是具有Enumerable mixin。这使我们可以将任何我们喜欢的东西视为“具有元素的东西”。因此,让我们可以在字符串 itself 的元素上插入+
而不是数组。为此,我们必须为字符串定义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
的定义由我决定,因此,我可以扫描某些 other 模式,而不用扫描每个 字符!例如,我可以扫描元音:
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
来使String la脚。让我们将整个功能拖到一个自定义类上。我们称之为VowelFinder!因此,我们以您开始的代码结束。