Я не абсолютный эксперт в этом, но Array Ruby написан как C-код. вот код для сглаживания! :
static VALUE
rb_ary_flatten_bang(ary)
VALUE ary;
{
long i = 0;
int mod = 0;
VALUE memo = Qnil;
while (i<RARRAY(ary)->len) {
VALUE ary2 = RARRAY(ary)->ptr[i];
VALUE tmp;
tmp = rb_check_array_type(ary2);
if (!NIL_P(tmp)) {
if (NIL_P(memo)) {
memo = rb_ary_new();
}
i += flatten(ary, i, tmp, memo);
mod = 1;
}
i++;
}
if (mod == 0) return Qnil;
return ary;
}
Как вы видите на этой строке,
i += flatten(ary, i, tmp, memo);
и вот реализация этой функции С сглаживания:
static long
flatten(ary, idx, ary2, memo)
VALUE ary;
long idx;
VALUE ary2, memo;
{
VALUE id;
long i = idx;
long n, lim = idx + RARRAY(ary2)->len;
id = rb_obj_id(ary2);
if (rb_ary_includes(memo, id)) {
rb_raise(rb_eArgError, "tried to flatten recursive array");
}
rb_ary_push(memo, id);
rb_ary_splice(ary, idx, 1, ary2);
while (i < lim) {
VALUE tmp;
tmp = rb_check_array_type(rb_ary_elt(ary, i));
if (!NIL_P(tmp)) {
n = flatten(ary, i, tmp, memo);
i += n; lim += n;
}
i++;
}
rb_ary_pop(memo);
return lim - idx - 1; /* returns number of increased items */
}
Свести! код напрямую вызывает функцию C flatten для любого элемента массива, который проверяет rb_check_array_type , он не возвращается к ruby-коду. Вместо этого он обращается к базовой структуре C напрямую, минуя вашу перегруженную реализацию.
Не уверен, как это переопределить, я думаю, что одним из способов может быть открытие Массива и переписывание сглаживания и сглаживания! функционировать как чистый рубин.
Вы получите удар по производительности, но затем сможете перегрузить его, как считаете нужным. И вы всегда можете использовать псевдонимы, чтобы иметь «flatten_native» и «flatten_native!» функция в вашем модифицированном массиве, чтобы вернуть perfs в некоторых случаях.