症状
var array : Array = [1, 2, 3];
var elem : int = array[1];
UnityScriptでArrayからintを取り出そうとしたりすると、以下の様な警告に悩まされます。
Warning: implicit downcast from Object to int
原因
intを[UnityScriptのArray][array]に入れてしまうと、intが[ボックス化][arrayboo]されてしまい、要素を取り出す時はすべてObject扱いになります。そのため、取り出す際にはなんらかの変換が必要になります。
対症療法1: 取り出してからintに変換
UnityScriptのas演算子によるキャストは参照型専用のため、array[1] as intと書いてすませることはできません。
代用として、.NET標準の[System.Convert.ToInt32][toint32]が使えます。これでObjectをintに変換できます。
var array : Array = [1, 2, 3];
var elem : int = System.Convert.ToInt32(array[1]);
対症療法2: ArrayごとList.<int>に変換
より安全なのは、Arrayの代わりに要素の型を一種類に固定したコンテナを使うことです。ここではすでにArrayがあるものとして、変換の方法を挙げていきます。
Listの[コンストラクタ][listctor]が変換に便利です。機能もほぼArrayの上位互換です。
using System.Collections.Generic;
// ...
var array : Array = [1, 2, 3];
var listOfInts : List.<int> = new List.<int>(array);
var elem : int = listOfInts[1];
対症療法3: Arrayごとint[]に変換
int[]も意外と機能は豊富です。伸び縮みこそできないものの、[System.Array][dotnetarray]のスタティックメソッド群は頼りになります。
for文で変換
for文を回してコピーする場合は、対症療法1のSystem.Convert.ToInt32が必要になります。目的と手段が逆になっている気もしますが、これが最もメモリが少なくすみます。
var array : Array = [1, 2, 3];
var ints : int[] = new int[array.length];
for (var i = 0; i < ints.length; i++) {
ints[i] = System.Convert.ToInt32(array[i]);
}
var elem : int = ints[1];
ToBuiltinで変換 (使えたら)
[Unityのリファレンス][array]には、ToBuiltinというそのもののメソッドがあります。しかし、プリミティブ型では[うまく動かない][tobuiltinsucks]ようです。
var array : Array = [1, 2, 3];
var listOfInts : int[] = array.ToBuiltin(int) as int[];
var elem : int = listOfInts[1];
List#ToArrayで変換
富豪的には、Listを経由して[ToArray][toarray]を使うのが記述が短くすみます。
var array : Array = [1, 2, 3];
var listOfInts : int[] = new List.<int>(array).ToArray();
var elem : int = listOfInts[1];
根治: Arrayを使わない
以上に紹介した方法はいずれも対症療法です。Arrayを受け渡ししないのが安全性的にも速度的にも一番です。ほとんどの場合はList.<int>で置き換えることができます。
筆者の場合は手を抜いてブラウザ用のJSONパーサを持ってきた時にこの警告に遭遇しました。その後Json.NETに乗り換えました。
他の原因
Arrayを使わない時でも、以下のような記述をするとimplicit downcastの警告が出ます。
var array : int[] = [1, 2, 3];
var elem;
elem = array[1];
var foo : int = elem;
これは変数elemの型がデフォルトのObjectになったことによるものです。var elem : int;と宣言しておくことで警告も速度悪化も避けることができます。他の方法として、var elem = array[1];のように宣言と初期化を同時に行うと[型推論が働くので][perf]記述を短くすますことが出来ます。
他にこの警告が出た例があれば教えて下さい。
リンク
- [Unity - Scripting API: Array][array]
- [System.Convert.ToInt32 - MSDN][toint32]
- [Array メソッド (System) - MSDN][dotnetarray]
- [List.ToArray メソッド (System.Collections.Generic) - MSDN][toarray]
- [Unity Script Reference - Overview: Performance Optimization][perf]
- [unityscript/Array.boo at master - bamboo/unityscript][arrayboo]
[perf]: http://docs.unity3d.com/412/Documentation/ScriptReference/index.Performance_Optimization.html
[toint32]: http://msdn.microsoft.com/en-us/library/system.convert.toint32.aspx
[array]: docs.unity3d.com/ScriptReference/Array.html
[dotnetarray]: http://msdn.microsoft.com/ja-jp/library/System.Array_methods(v=vs.80).aspx
[tobuiltinsucks]: http://d.hatena.ne.jp/shinriyo/20120822/p1
[toarray]: http://msdn.microsoft.com/ja-jp/library/x303t819(v=vs.80).aspx
[listctor]: http://msdn.microsoft.com/ja-jp/library/fkbw11z0(v=vs.80).aspx
[arrayboo]: https://github.com/bamboo/unityscript/blob/master/src/UnityScript.Lang/Array.boo