技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

型推論とは

型推論とは、メソッド内のローカル変数を初期値付きで(右辺がある状態で)宣言する際に、通常の型宣言の代わりに"var"という仮の型を使用できるという文法です。
"var"を用いた際は、コンパイル時に自動で型を判断し、その型への置き換えが行われます。
 
C#では3.0(2007/11)から導入されており、現在ではお馴染みの文法と言えるでしょう。
Javaでは長らく導入されていませんでしたが、10(2018/03)でついに導入されました。
今後はJavaの案件でも目にすることが増えると思います。
 
型推論を用いることで、冗長な型宣言をすっきりさせることができます。
C#の例で言うと、下記のコードで、定義時に"List<string>"と型を指定している箇所は、"var"に書き変えることができます。
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[ ] args)
        {
            //List<string> list = new List<string>();
            var list = new List<string>();
            list.Add("Hello ");
            list.Add("World");
            list.Add("!");
            foreach(string str in list)
            {
                Console.Write(str);
            }
            Console.WriteLine("");
            Console.ReadKey(true);
        }
    }
}
 
また、ソース修正で型を変えるような場合にも、"var"と記述した部分は変更する必要がなくなるので、ソース修正が楽になるというメリットもあります。
 
-------------------
 
型はコンパイル時に決まるため、実行時に動的に型が変わることはありません。
例えば、下記のようなコードはコンパイルエラーになります。
((22,20): error CS0029: 型 'int' を型 'System.Collections.Generic.List<string>' に暗黙的に変換できません。)
誤って意図しない型を代入しようとした場合はコンパイル時にエラーとして検知できるので、その意味では安心して使えます。
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[ ] args)
        {
            var list = new List<string>();
            list.Add("Hello ");
            list.Add("World");
            list.Add("!");
            foreach(string str in list)
            {
                Console.Write(str);
            }
            Console.WriteLine("");
            list = 1 + 2; // 途中でintのような使い方をするとコンパイルエラー
            Console.WriteLine(list.ToString());
            Console.ReadKey(true);
        }
    }
}
 
ちなみに、「型推論」と似た概念として「動的型付け」というものがあるのですが、こちらは途中で異なる型を代入すると変数の型そのものが変わり処理が続行されます。
例えば、JavaScriptでは動的型付けが採用されており、予約語も"var"を用いるため、「型推論」と混同されがちです。
「動的型付け」の方は誤って意図しない型を代入しても実行するまで気付くことができず、実行時に出るエラーが分かりにくいものだったり、そもそもエラーが出ないこともあるので、注意が必要です。
 
-------------------
 
以上のように便利な型推論ですが、可読性を落とすデメリットもあります。
具体的に言うと、変数宣言時の型が一目瞭然ではない場合に用いると可読性を落とします。

例えば、下記のコードで変数宣言時の型を知るためには、"MyFunc"の仕様を知っている必要があります。
"MyFunc"のような独自の関数でなくても、チーム内での知名度が低い関数を用いる場合は注意が必要です。
 
var hoge = MyFunc();
 
また、"int"や"string"のような基本的な型に対して用いるのも、元々型宣言が冗長ではないという意味で型推論を使用するメリットが少ないので、他の開発者に違和感を抱かせてしまう可能性があります。