[RUBY] Comportement lorsque chacun est exécuté dans la plage inverse

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.

Instanciation de plage

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

Plage # chaque comportement

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

Description de la plage # chacun

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

Implémentation de la plage # chacun

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

Comportement lorsque chacun est exécuté dans la plage inverse
Comportement lorsque le caractère générique (**) est spécifié dans ruby
Lorsque le projet n'est pas affiché dans eclipse
Ebean.update () n'est pas exécuté dans le modèle hérité.
ORA-08177 lorsque Spring Batch est exécuté en continu dans Oracle
Jusqu'à ce que le code soit exécuté
Le comportement de la classe # getClassLoader change selon qu'elle est exécutée dans l'EDI ou dans le fichier jar.
Comment afficher la valeur lorsqu'il y a un tableau dans le tableau
Ordre de traitement dans le programme
Modifier le traitement lorsque le bouton de RecyclerView est enfoncé pour chaque liste
Erreur lors de la finalisation du membre de la classe Entity utilisé dans SpringWebFlux
Lorsque le nom de la classe du bean est dupliqué
[Rails] Annoter n'est pas exécuté lors de la migration
Spring Autowired est écrit dans le constructeur
Quelle est la méthode principale en Java?
Possibilité lors du déploiement sur EC2 mais rien n'est affiché dans le journal des erreurs
Comment définir quand "Le constructeur Empty () n'est pas visible" se produit dans junit