ruby中的enumerable和iterator方法之间的区别

时间:2017-01-31 08:55:45

标签: ruby

我学习红宝石。

我想知道ruby中的enumerable和iterator方法之间的区别,以及为什么我们使用枚举器方法..

对我来说两个看起来都一样。

我想知道两者之间的区别

普通迭代器方法

   [TestFixture]
    public class TestsSample
    {

        [SetUp]
        public void Setup() { }


        [TearDown]
        public void Tear() { }

        [Test]
        public void Pass()
        {
            Console.WriteLine("test1");
            Assert.True(true);
        }

        [Test]
        public void Fail()
        {
            Assert.False(true);
        }

        [Test]
        [Ignore("another time")]
        public void Ignore()
        {
            Assert.True(false);
        }

        [Test]
        public void Inconclusive()
        {
            Assert.Inconclusive("Inconclusive");
        }
    }

每个使用枚举器

3.times do
|x| puts x
end

也适用于字符串

enumerator = 3.times
enumerator.each do
|x| puts x
end

使用枚举器对象

"scriptkiddie".each_char{|x| puts x}

使用枚举器有什么好处。我应该在哪里使用Enumerator?

请帮助我理解差异

1 个答案:

答案 0 :(得分:5)

回答原来的问题

[1,2,3].each.is_a?(Enumerable)
#=> true
[1,2,3].each.is_a?(Enumerator)
#=> true
[1,2,3].each.class.ancestors
#=> [Enumerator, Enumerable, Object, Kernel, BasicObject]

是的,"迭代器"当没有使用块时,each返回Enumerator

但是,如果你只是学习Ruby并希望迭代一个数组/范围/哈希,那就知道使用each将涵盖大多数情况:

[1, 2, 3].each do |element|
  puts element
end
# 1
# 2
# 3

('a'..'e').each do |element|
  puts element
end
# a
# b
# c
# d
# e

{'a' => 1, 'b' => 2}.each do |key, value|
  puts key
  puts value
end
# a
# 1
# b
# 2

在您的级别上,您不必关心这些方法的定义位置,类别或模块或方式。

最后,for loops不应该在Ruby中使用,因为它们可以显示奇怪的行为。

您更新的问题

你提出的问题更加清楚,这很好。请注意,更改可能会被忽视,特别是如果您已经接受了答案。

3.times

3.times do |x|
  puts x
end

enumerator = 3.times
enumerator.each do |x|
  puts x
end

像这样使用,两者完全相同。由于第二个更详细,enumerator可能不会在其他任何地方使用,因此没有理由使用第二个变体。无论如何enumerator3.times更长:)

请注意,|x|应与块开始位于同一行。 Rubocop可以帮到你。

each_char

"scriptkiddie".each_char{|x| puts x}
"scriptkiddie".enum_for(:each_char).each{|x| puts x}

同样,如果您只是创建一个枚举器并直接在其上调用each,则没有理由使用第二个变体。

为什么要使用Enumerator?

链接方法

使用Enumerator的一个原因是能够链接Enumerable方法:

puts 3.times.cycle.first(7)
#=> [0, 1, 2, 0, 1, 2, 0]

"script".each_char.with_index{|c, i|
  puts "letter #{i} : #{c}"
}
# letter 0 : s
# letter 1 : c
# letter 2 : r
# letter 3 : i
# letter 4 : p
# letter 5 : t

无限列表

枚举器还可以使用无限列表。

require 'prime'

every_prime = Prime.each
p every_prime.first(20)
#=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]

p every_prime.lazy.select{|x| x > 1000}.first(3)
#=> [1009, 1013, 1019]

自定义迭代

可以为自定义迭代定义新的枚举器:

require 'date'

def future_working_days(start_date = Date.today)
  date = start_date
  Enumerator.new do |yielder|
    loop do
      date += 1
      yielder << date unless date.saturday? || date.sunday?
    end
  end
end

puts future_working_days.take(3)
# 2017-02-01
# 2017-02-02
# 2017-02-03