Als ich mich umdrehte, tat ich nichts und bekam keinen Fehler, und ich war süchtig danach, weil die Verarbeitung so weiterging, wie sie war, also machte ich ein Memorandum.
Im Fall von Startpunkt <Endpunkt, Startpunkt> Endpunkt kann die Instanziierung problemlos erstellt werden.
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
Das Problem ist, wenn Sie jeden Bereich in umgekehrter Reihenfolge drehen.
aaa.each {|i| puts i}
1
2
3
4
5
=> 1..5
ccc.each {|i|puts i}
=> 5..1
Laut Rurima wird Range # jeweils mit succ iteriert. https://docs.ruby-lang.org/ja/latest/method/Range/i/each.html
Wenn man sich die Beschreibung von succ für Integer ansieht, scheint es, dass einfach die nächste Ganzzahl zurückgegeben wird.
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
Wahrscheinlich wird statischer VALUE range_each (VALUE range) aufgerufen, und da die while-Bedingung danach nicht erfüllt ist, scheint die Verarbeitung abgeschlossen zu sein, ohne auch nur eine Runde zu schleifen.
https://github.com/ruby/ruby/blob/trunk/range.c#L833
static VALUE
range_each(VALUE range)
{
//...Kürzung
if (!NIL_P(end))
range_each_func(range, each_i, 0);
else
for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
rb_yield(beg);
//...Kürzung
}
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