for文の初期化変数でlengthを参照する際の注意

見事にハマったのでメモ。
次のようなステートメントを実行すると、Flashタイムアウトを起こしてしまいます。

var myArray = new Array(3);
for (var i:uint = myArray.length; i >= 0; i--) {
  trace(i);
}

どこに問題があるのかまるで分からなかったのですが、どうやら初期化変数のiにuint型を指定していたのが良くないみたいです。ドキュメントを調べてみると、Arrayオブジェクトのlengthプロパティの型はuintで指定されているし、特に問題はなさそうなのですが、uintで指定するとiに4294505655とかいうとてつもなく大きな値が返され、結果として莫大な数のループが発生し、タイムアウトを起こしてしまっていたようなのです。

ちなみにStringオブジェクトのlengthの型はint指定されていますが、やはりiの値をuintにするとタイムアウトを起こします。

var myString:String = new String("123");
for (var i:uint = myString.length; i >= 0; i--) {
  trace(i);
}

どちらのケースも、変数iの型をintかNumberにしてやると、期待通り動いてくれるます。うーん、不思議。iにlengthの値を代入する際に黙示的なキャストがされていると考えてみても、Number型の3はuintに(明示的に)キャストしても3だしなぁ…。

var myNumber:Number = 3;
trace(uint(myNumber));
//output 3

理由はわからないけど、ともかくfor文の時のiにlengthの参照をさせるときは、全部int指定ってことで覚えておきます。


【2007/11/09追記】
理由がわかりました。恥ずかしい。lengthの型とか関係ないです。

for (var i:uint = 3; i >= 0; --i) {
  trace(i);
}

でも同様にタイムアウト起こします。っつーか、エントリー書く前に試さない俺。バカすぎ。つい先日も同じような先走りエントリーをしたばかりなのに。

for文はiの値が3, 2, 1, 0と入った後で処理を停止するのではなく、再度条件判定のためにi--を行うんですね。その結果iに-1という値が代入されるのですが、これがuintで型指定されているために、4294967295という値に黙示的にキャストされ、ここで莫大な数のループが発生してしまっていたようです。

var myNum:Number = -1;
trace(uint(myNum));
//output 4294967295

for文の仕組みすら正しく理解できていませんでした。ひたすら恥ずかしいです。