Quand j'ai tourné chacun, je n'ai rien fait et je n'ai pas eu d'erreur, et j'en étais accro parce que le traitement continuait comme il était, alors j'ai rédigé une note.
Dans le cas du point de départ <point de fin, point de départ> point de fin, l'instanciation peut être créée sans aucun problème.
aaa = Range.new(1,5)
=> 1..5
bbb = 1..5
=> 1..5
ccc = Range.new(5,1)
=> 5..1
ddd = 5..1
=> 5..1
Range#each
Le problème est lorsque vous tournez chacun dans la plage générée dans l'ordre inverse.
aaa.each {|i| puts i}
1
2
3
4
5
=> 1..5
ccc.each {|i|puts i}
=> 5..1
Selon Rurima, Range # chacun est itéré avec succ. https://docs.ruby-lang.org/ja/latest/method/Range/i/each.html
En regardant la description de succ pour Integer, il semble qu'il renvoie simplement le prochain entier.
aaa.begin.class
=> Integer
https://docs.ruby-lang.org/ja/2.5.0/method/Integer/i/next.html
aaa.begin
=> 1
aaa.begin.succ
=> 2
ccc.begin
=> 5
ccc.begin.succ
=> 6
Probablement la valeur statique VALUE range_each (VALUE range) est appelée, et comme la condition while n'est pas satisfaite après cela, il semble que le traitement soit terminé sans boucler ne serait-ce qu'un tour.
https://github.com/ruby/ruby/blob/trunk/range.c#L833
static VALUE
range_each(VALUE range)
{
//...réduction
if (!NIL_P(end))
range_each_func(range, each_i, 0);
else
for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
rb_yield(beg);
//...réduction
}
https://github.com/ruby/ruby/blob/trunk/range.c#L239
static void
range_each_func(VALUE range, int (*func)(VALUE, VALUE), VALUE arg)
{
int c;
VALUE b = RANGE_BEG(range);
VALUE e = RANGE_END(range);
VALUE v = b;
if (EXCL(range)) {
while (r_less(v, e) < 0) {
if ((*func)(v, arg)) break;
v = rb_funcallv(v, id_succ, 0, 0);
}
}
else {
while ((c = r_less(v, e)) <= 0) {
if ((*func)(v, arg)) break;
if (!c) break;
v = rb_funcallv(v, id_succ, 0, 0);
}
}
}
https://github.com/ruby/ruby/blob/trunk/range.c#L157
/* compares _a_ and _b_ and returns:
* < 0: a < b
* = 0: a = b
* > 0: a > b or non-comparable
*/
static int
r_less(VALUE a, VALUE b)
{
VALUE r = rb_funcall(a, id_cmp, 1, b);
if (NIL_P(r))
return INT_MAX;
return rb_cmpint(r, a, b);
}
Recommended Posts