Recherche
Peut être aimerez-vous...
Sections du site
Sites Neamar
Lisez ces articles !
| AS3 snippet : for each dans les cas extrêmes |
|
| Programmation et tuning - as3 |
| Écrit par Neamar |
| Lundi, 07 Juin 2010 17:41 |
|
Actionscript3 offre, comme beaucoup de langage, une structure de boucle sur les propriétés dynamiques d'un objet : for each.. in (à ne pas confondre avec forEach qui est une propriété de la classe Array). La documentation est assez claire pour l'utilisation générale : Mais que se passe-t-il si on modifie le tableau pendant l'itération ? La doc reste muette sur ce sujet… alors il faut tester. Cas générique :var Test:search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array = new search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array(1, 2, 3, 4, 5); for each(var Item:search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html&filter=0&num=100&btnI=lucky">int in Test) trace(Item); Qui nous donne bien : 1 2 3 4 5 Première information : for each semble conserver l'ordre des données. Mais c'est à confirmer plus tard… AjoutDeuxième test : et si on modifie le tableau dans le for each, par exemple en ajoutant un élément ? Distinguons deux cas : l'ajout à la fin (méthode push()) et l'ajout au début (unshift()). Ajout par la finfor each(var Item:search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html&filter=0&num=100&btnI=lucky">int in Test) { trace(Item); if (Item == 5) Test.push(6,7,8); } 1 2 3 4 5 6 7 8 L'ajout par la fin marche donc correctement. Ajout par le débutvar Test:search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array = new search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array(1, 2, 3, 4, 5); for each(var Item:search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html&filter=0&num=100&btnI=lucky">int in Test) { trace(Item); if (Item == 5) Test.unshift(6,7,8); } Cette fois les résultats sont plus intéressants : 1 2 3 4 5 3 4 5 3 4 5 3 4 5 3 4 5 3 4 5 … Que voit-on ? Les 5 premiers éléments se tracent correctement, puis on effectue le unshift(). Et là, plutôt que d'afficher les nouveaux éléments, flash recule de trois éléments et recommence à afficher 3-4-5, 5 rajoute à nouveau des éléments, et ainsi de suite. Un code à priori correct s'avère donc faux, et pire fait crasher l'animation avec une boucle infinie ! Suppression d'un élémentComme pour l'ajout, il faut distinguer la suppression d'un élément à la fin (méthode pop()) et par le début (méthode shift()). Suppression par la finvar Test:search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array = new search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array(1, 2, 3, 4, 5); for each(var Item:search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html&filter=0&num=100&btnI=lucky">int in Test) { trace(Item); if (Item == 2) Test.pop(); } 1 2 3 4 Rien à dire, comportement normal : on a supprimé le 5 qui n'est donc pas affiché. Suppresion par le débutvar Test:search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array = new search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array(1, 2, 3, 4, 5); for each(var Item:search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html&filter=0&num=100&btnI=lucky">int in Test) { trace(Item); if (Item == 2) Test.shift(); } 1 2 4 5 C'est le même comportement que pour l'ajout : les index sont automatiquement décalés. Flash est sur l'index #1, fait glisser tout le monde (la valeur 3 passe en #1) et incrémente la propriété actuellement examinée : #2, ce qui fait que le 3 n'est jamais testé. Changement de la variable pointéeEt si le tableau est entièrement modifié pendant l'itération ? Pour bien comprendre, je vais effectuer la modification sur la valeur 2 : var Test:search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array = new search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array(1, 2, 3, 4, 5); for each(var Item:search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html&filter=0&num=100&btnI=lucky">int in Test) { trace(Item); if (Item == 2) Test = new search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array(6,7,8,9,10); } Et le trace : 1 2 3 4 5 Pourtant, on pourrait s'attendre à ceci : 1 2 6 7 8 9 10 En fait, for each..in semble faire une référence vers l'objet pointé par Test à la première itération, puis ne travailler qu'avec cette référence sans se soucier du fait que Test pointe ensuite vers une autre variable. En fait, c'est la notion cachée de pointeur qui joue ici : l'objet pointé n'est plus le même (présence de new()). Ordre d'énumérationEnfin, que peut-on dire sur l'ordre d'énumération ? S'agit-il de l'ordre lexicographique ou de l'ordre dans lequel les valeurs sont ajoutées ? var Test:search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array = new search?q=Array%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:Array.html&filter=0&num=100&btnI=lucky">Array(); Test[3] = 1; Test[4] = 0; Test[2] = 2; Test[1] = 3; for each(var Item:search?q=int%20inurl:http://livedocs.adobe.com/flex/201/langref/%20inurl:int.html&filter=0&num=100&btnI=lucky">int in Test) { trace(Item); } 3 2 1 0 Bref, un affichage par index croissant. On peut donc tirer nos conclusions et complémenter la documentation floue :
Bon code ! |
| Mise à jour le Lundi, 07 Juin 2010 19:49 |
