覆盖'each'并'[]'我的数组子类,这有效,但'select'似乎忽略了它



我有一个类,我想让"each"产生另一个自定义对象,所以我写了这个:

class Fq_price_set < Array
 ...
  def [](i)
    # instead of returning an array, it returns an Fq_price_rec based on the array at i
    Fq_price_rec.new(super(i))
  end  
  def each
    c = 0
    until c == size
      yield self.[](c)
      c += 1
    end
  end
...
end

这是有效的:当我做

my_price_set.each {|rec| puts rec.class}

它显示Fq_ price_。类似地,

my_price_set.each {|rec| puts rec.mymethod}

为该方法调用输出正确的值。

但当我使用select时,例如

my_price_set.select {|rec| rec.mymethod == 1}

我收到一条错误消息,"数组的未定义方法"mymethod":。。。因此,rec(在"select"中)不是Fq_price_rec,而是一个数组(Fq_prese_rec是其中的一个子类)。我(显然是错误的)认为重写"each"意味着像"select"这样的迭代方法会使用它,即子类的"each"版本。是简单的答案,我也必须覆盖"选择",还是有一个更优雅的解决方案。

是的,我是Ruby的新手。

TIA

为什么不取消从Array继承,只使用include Enumerable

class Fq_price_set
  include Enumerable
  def initialize(actual_array)
    @actual_array = actual_array
  end
  # Make [] and each refer to values from @actual_array
end

这样的子类数组不太好用。原因是很多Array都是在C语言的Ruby解释器中实现的;Array实现对Array的行为进行了某些假设,以避免从C实现到Ruby land再到C的额外往返成本。

特别是,select的实现如下所示:

static VALUE
rb_ary_select(VALUE ary)
{
    VALUE result;
    long i;
    RETURN_ENUMERATOR(ary, 0, 0);
    result = rb_ary_new2(RARRAY_LEN(ary));
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) {
            rb_ary_push(result, rb_ary_elt(ary, i));
        }
    }
    return result;
}

让你悲伤的部分是:

RARRAY_PTR(ary)[i]

Ruby直接访问内部C数组,而不需要经过您版本的[]运算符。

所以你应该听格林先生说:

  • 包括可枚举
  • 添加任何需要像数组一样嘎嘎作响的额外方法和运算符

最新更新