1. 概要

このチュートリアルでは、Scalaの型推論について学び、さまざまな型を調べます。 次に、使用を避けるのが最適な時期を知るための制限のいくつかを学びます。 また、途中でいくつかの興味深い例を見ていきます。

2. Scalaでは型宣言はオプションです

Scalaコンパイラーは、コンテキスト情報から式のタイプを自動的に推測できます。 したがって、型を明示的に宣言する必要はありません。 この機能は、一般に型推論と呼ばれます。 コードの冗長性を減らし、より簡潔で読みやすくするのに役立ちます。 Scalaでは、変数宣言、関数の戻り型、無名関数のパラメーターで型推論を確認できます。

それぞれを詳しく学びましょう。

3. 変数の型推論

型推論の最も一般的なアプリケーションは、変数宣言に見られます。 コンパイラは指定された初期値に基づいて型を推測できるため、宣言で型を省略できます。 たとえば、初期値が二重引用符で囲まれている場合、コンパイラは型をStringと見なします。

一重引用符で囲まれている場合は、Charなどのタイプを取ります。 変数を宣言して整数値を指定し、何が起こるかを見てみましょう。

val integerObj = 10
println(integerObj.getClass)  // prints int

予想どおり、変数のタイプがintとして出力されていることがわかります。 それでは、他の基本的なタイプの例をさらにいくつか見てみましょう。

val doubleObj = 10.01   // infers double type
val charObj = 'a'       // infers char type
val stringObj = "hello" // infers java.lang.String type
val booleanObj = true   // infers boolean type

4. 関数の型推論

変数型の推論と同様に、Scalaコンパイラーは関数の戻り型も推論できます。 整数値の2乗を計算し、その戻り型を省略するための単純な関数を見てみましょう。

def squareInt(num:Int) = {
  num * num
}

それでは、関数を呼び出して、どのタイプが返されるかを確認しましょう。

val square = squareInt(2)
println(square.getClass)    // prints int

もう1つ気付くのは、returnキーワードがないことです。 return type に型推論を選択する場合は、returnキーワードも省略する必要があります。 そうしないと、コンパイル時にエラーが発生します。

ただし、再帰関数の場合、コンパイラーは混乱し、戻り値の型を検出できなくなります。 この制限については、次のセクションで詳しく説明します。

5. パラメータの型推論

デフォルトでは、Scalaは関数パラメーターのタイプを推測できません。 それにもかかわらず、この規則にはいくつかの例外があります。 無名関数の場合、Scalaコンパイラーはパラメータータイプを推測できます。

reduce 関数を使用して、要素のリストの合計を計算してみましょう。

val list = List(1,2,3,4)
val sum1 = list.reduce((a:Int,b:Int) => a + b)
val sum2 = list.reduce((a, b) => a + b)

ここでは、reduce関数がabの2つのパラメーターを持つ無名関数を受け取ることがわかります。 最初の式では、型を明示的に宣言しています。 2つ目では、パラメータタイプを省略しました。 パラメータのタイプaおよびbは、入力リストの要素タイプから推測されます。

どちらの式も有効であり、同じ結果が得られます。 2番目の表現は、最初の表現よりもクリーンで簡潔、かつエレガントであることがわかります。

6. 型推論の制限

型推論機能は、ほとんどの場合に役立ちます。 クリーンで簡潔なコードを書くのに役立ちます。 ただし、type を明示的に宣言する必要がある場合があります。たとえば、変数を宣言するときに特定のデータ型が必要な場合や、再帰関数を定義する場合などです。

10進数以外の数値はすべて整数型として推測され、10進数値はすべてdouble型として推測されます。 これは、ほとんどのユースケースで機能します。 ただし、場合によっては、より具体的な型宣言が必要になります。 byte値の変数を宣言する必要があると仮定しましょう。

val byteVarDeclared:Byte = 1

ここでは、型を明示的に宣言する必要があることがわかります。そうしないと、コンパイラはint型を想定します。

それでは、再帰関数の定義を見てみましょう。

def sumRecursive(list:List[Int]):Int={
  if(list.size > 1) {
    list.head + sumRecursive(list.drop(1))
  } else {
    list.head
  }
}

この関数の戻り型を省略しようとすると、コンパイルエラーが発生します:「再帰メソッドsumRecursiveは結果型」を必要とします。

7. 結論

この記事では、Scalaで型推論機能がどのように機能するかを学びました。 Scalaコンパイラーは、変数宣言の型、関数の戻り型、場合によっては関数のパラメーターも推測できることを学びました。 また、型推論を適用できないいくつかの制限もあります。

いつものように、この記事のコード全体は、GitHubから入手できます。