Scala Language
Wnioskowanie typu
Szukaj…
Wnioskowanie typu lokalnego
Scala ma wbudowany w język potężny mechanizm wnioskowania typu. Mechanizm ten określa się jako „wnioskowanie typu lokalnego”:
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
Kompilator może wywnioskować rodzaj zmiennych z wyrażenia inicjującego. Podobnie, zwracany typ metod można pominąć, ponieważ są one równoważne typowi zwracanemu przez treść metody. Powyższe przykłady są równoważne z poniższymi deklaracjami typu jawnego:
val i: Int = 1 + 2
val s: String = "I am a String"
def squared(x : Int): Int = x*x
Wnioskowanie typu i generyczne
Kompilator Scala może również wydedukować parametry typu, gdy wywoływane są metody polimorficzne lub gdy tworzone są klasy ogólne:
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")
Powyższa forma wnioskowania typu jest podobna do Diamond Operator , wprowadzonego w Javie 7.
Ograniczenia wnioskowania
Istnieją scenariusze, w których wnioskowanie typu Scala nie działa. Na przykład kompilator nie może wywnioskować typu parametrów metody:
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
Kompilator nie może wywnioskować typu zwracanego metod rekurencyjnych:
// 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)
Zapobieganie wnioskowaniu Nic
Na podstawie tego postu na blogu .
Załóżmy, że masz taką metodę:
def get[T]: Option[T] = ???
Kiedy próbujesz wywołać go bez określenia parametru ogólnego, Nothing
się Nothing
wywnioskuje, co nie jest zbyt przydatne w rzeczywistej implementacji (a jego wynik nie jest użyteczny). W następującym rozwiązaniu kontekst kontekstowy NotNothing
może uniemożliwić użycie metody bez określenia oczekiwanego typu (w tym przykładzie RuntimeClass
jest również wykluczony, ponieważ dla ClassTags
nie Nothing
, ale wywnioskowano 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]] = ???
}
Przykładowe użycie:
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()
}