1

我可以编写一个简短的示例来验证内部调用to_a的情况。这里是:Enumerableeach

class MyFooClass
  include Enumerable
  def initialize
    @members = [1, 2, 3]
  end
  def each
    puts "each is now called"
    @members.each{ |m| yield(m) }
  end
end

a = MyFooClass.new
puts "let us convert to array"
g = a.to_a

输出是:

let us convert to array
each is now called

请注意,each它不是 的成员Enumerable,而是to_a。此外,如果我从类中删除 的定义each,则代码会崩溃并显示以下消息:

in `to_a': undefined method `each' for #<MyFooClass:0x997c1ac @members=[1, 2, 3]> (NoMethodError)

我想知道是否有关于此的 Ruby 官方文档,该文档将记录to_a(它是 的成员Enumerable)在您的类中通过each方法的事实。请不要将我指向to_a. 我不认为这是一个答案。

4

3 回答 3

5

来自精美手册

mixin 为集合类提供了Enumerable几种遍历和搜索方法,以及排序的能力。该类必须提供一个方法each,该方法产生集合的连续成员。

强调我的。所以 Enumerable 的所有迭代行为都是基于类的each方法;minEnumerable 接口 ( , max, sort)的排序部分使用<=>,但这在这里并不重要。

提供的each方法是 Enumerable 必须与混合它的类交互的唯一定义方式。Enumerable 提供了一个to_a方法,因此它必须使用它each来实现它。

顺便说一句,Enumerable 尽量不调用to_a,除非它必须调用,它试图将所有内容都保留为 Enumerable,以避免不得不用尽枚举来构建一个在时间和空间上都可能很昂贵的数组。Yossi指出的答案更多是关于Enumerable何时to_a调用而不是如何调用(但这个答案仍然很有趣;)。

于 2011-09-12T08:44:02.623 回答
1

注意id_each代码中的#to_a

static VALUE
enum_to_a(int argc, VALUE *argv, VALUE obj)
{
    VALUE ary = rb_ary_new();

    rb_block_call(obj, id_each, argc, argv, collect_all, ary);
    OBJ_INFECT(ary, obj);

    return ary;
}

有关更深入的解释,请参阅问题。

于 2011-09-12T08:28:07.587 回答
0

除了 mu 指出的手册中的苦行解释外,Pickaxe 书中也有以下段落,它是事实上的 Ruby 入门书籍之王:

好吧,由于 mixins 和模块 Enumerable 的魔力,你的类可以支持所有这些整洁的特性。您所要做的就是编写一个名为 each 的迭代器,它依次返回集合中的元素。混入 Enumerable,突然你的类支持 map、include? 和 find_all? 等东西。

于 2011-09-12T09:16:49.207 回答