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()
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow