我有一个类,我想让"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数组,而不需要经过您版本的[]
运算符。
所以你应该听格林先生说:
- 包括可枚举
- 添加任何需要像数组一样嘎嘎作响的额外方法和运算符