Scalaコンパイラが式の型を推論できることが多いので、明示的に型を宣言する必要はありません。
型の省略
val businessName = "Montreux Jazz Café"
コンパイラはbusinessNameがStringだと検知できます。これはメソッドでも同様に動きます。
def squareOf(x: Int) = x * x
コンパイラは戻り値の型がIntだと推論できるので、明示的な戻り値の型は必要ありません。
再帰的メソッドでは、コンパイラは結果の型を推論できません。こちらはこの理由でコンパイラが失敗するプログラムです。
def fac(n: Int) = if (n == 0) 1 else n * fac(n - 1)
ポリモーフィックメソッドが呼ばれる時やジェネリッククラス がインスタンス化される場合も型パラメータの指定は強制ではありません。Scalaコンパイラは文脈あるいはメソッドやコンストラクタの実際の引数から、指定されていない型パラメータを推論します。
こちらは2つの例です。
case class MyPair[A, B](x: A, y: B)
val p = MyPair(1, "scala") // 型: MyPair[Int, String]
def id[T](x: T) = x
val q = id(1) // 型: Int
コンパイラは型AとBが何であるかを見つけ出すためにMyPairの引数の型を使用します。xの型も同様です。
パラメータ
コンパイラはメソッドのパラメータ型を決して推論しません。しかし、関数が引数として渡されている場合は、無名関数のパラメータ型を推論できます。
Seq(1, 3, 4).map(x => x * 2) // List(2, 6, 8)
mapのパラメータはf: A => Bです。Seqの中に整数が入っているので、コンパイラはAがIntだと知っています(つまり、このxは整数です)。したがってコンパイラはx * 2からBが型Intであると推論できます。
型推論に頼らない時
一般的には、パブリックなAPIで公開されているメンバーの型を宣言したほうが読みやすいと考えられています。そのため、ユーザーに公開するAPIではあなたのコードの型を明示することをお勧めします。
また、型推論は特定の型を推論することがあります。次のように書いたとします。
var obj = null
これ以上進められず、再割り当てができません。
obj = new AnyRef
こちらはコンパイルできません。objに推論された型はNullだからです。その型の唯一の値がnullなので、他の値を代入できれません。