サーチ…


ローカル型推論

Scalaには強力な型推論機構が組み込まれています。このメカニズムは「ローカルタイプ推論」と呼ばれます。

val i = 1 + 2                  // the type of i is Int
val s = "I am a String"        // the type of s is String
def squared(x : Int) = x*x     // the return type of squared is Int

コンパイラは、初期化式から変数の型を推論できます。同様に、メソッドの戻り型は、メソッド本体から返される型と等価であるため、省略することができます。上記の例は、以下の明示的な型宣言に相当します。

val i: Int = 1 + 2               
val s: String = "I am a String" 
def squared(x : Int): Int = x*x     

タイプ推論とジェネリックス

Scalaコンパイラは、多態性メソッドが呼び出されるとき、またはジェネリッククラスがインスタンス化されるときに型パラメータを推定することもできます:

case class InferedPair[A, B](a: A, b: B)

val pairFirstInst = InferedPair("Husband", "Wife")  //type is InferedPair[String, String]
    
// Equivalent, with type explicitly defined
val pairSecondInst: InferedPair[String, String] 
                      = InferedPair[String, String]("Husband", "Wife")  

上記の型推論の形式は、Java 7で導入されたDiamond Operatorに似ています。

推論の限界

Scalaの型推論が機能しないシナリオがあります。たとえば、コンパイラはメソッドパラメータの型を推論することはできません。

def add(a, b) = a + b  // Does not compile
def add(a: Int, b: Int) = a + b // Compiles
def add(a: Int, b: Int): Int = a + b // Equivalent expression, compiles

コンパイラは、再帰メソッドの戻り値の型を推論することはできません。

// Does not compile
def factorial(n: Int) = if (n == 0 || n == 1) 1 else n * factorial(n - 1)
// Compiles
def factorial(n: Int): Int = if (n == 0 || n == 1) 1 else n * factorial(n - 1)

何も推測しないようにする

このブログの投稿に基づいています。

次のようなメソッドがあるとします。

  def get[T]: Option[T] = ???

ジェネリックパラメータを指定せずに呼び出そうとすると、 Nothingは推測されますが、これは実際の実装にはあまり役に立ちません(その結果は有用ではありません)。次のソリューションでは、 NotNothingコンテキストバインドによって、期待される型を指定せずにメソッドを使用することを防ぐことができます(この例では、 RuntimeClassNothingではなくClassTags RuntimeClassが推測されます)。

@implicitNotFound("Nothing was inferred")
sealed trait NotNothing[-T]

object NotNothing {
  implicit object notNothing extends NotNothing[Any]
  //We do not want Nothing to be inferred, so make an ambigous implicit
  implicit object `\n The error is because the type parameter was resolved to Nothing` extends NotNothing[Nothing]
  //For classtags, RuntimeClass can also be inferred, so making that ambigous too
  implicit object `\n The error is because the type parameter was resolved to RuntimeClass` extends NotNothing[RuntimeClass]
}

object ObjectStore {
  //Using context bounds
  def get[T: NotNothing]: Option[T] = {
    ???
  }
  
  def newArray[T](length: Int = 10)(implicit ct: ClassTag[T], evNotNothing: NotNothing[T]): Option[Array[T]] = ???
}

使用例:

object X {
  //Fails to compile
  //val nothingInferred = ObjectStore.get
  
  val anOption = ObjectStore.get[String]
  val optionalArray = ObjectStore.newArray[AnyRef]()
  
  //Fails to compile
  //val runtimeClassInferred = ObjectStore.newArray()
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow