Suche…


Lokale Typinferenz

Scala verfügt über einen leistungsfähigen, in die Sprache integrierten Typinterferenzmechanismus. Dieser Mechanismus wird als "lokale Typinferenz" bezeichnet:

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

Der Compiler kann den Typ der Variablen aus dem Initialisierungsausdruck ableiten. Ebenso kann der Rückgabetyp von Methoden weggelassen werden, da sie dem vom Methodenhauptteil zurückgegebenen Typ entsprechen. Die obigen Beispiele entsprechen den unten angegebenen expliziten Typdeklarationen:

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

Typ Inferenz und Generics

Der Scala-Compiler kann auch Typparameter ableiten, wenn polymorphe Methoden aufgerufen werden oder wenn generische Klassen instanziiert werden:

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")  

Die obige Form der Typeninferenz ähnelt dem in Java 7 eingeführten Diamond Operator .

Einschränkungen für Inferenz

Es gibt Szenarien, in denen die Scala-Typinferenz nicht funktioniert. Zum Beispiel kann der Compiler nicht auf die Art der Methodenparameter schließen:

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

Der Compiler kann nicht auf den Rückgabetyp rekursiver Methoden schließen:

// 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)

Keine Schlüsse ziehen

Basierend auf diesem Blogeintrag .

Angenommen, Sie haben eine Methode wie diese:

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

Wenn Sie versuchen, ihn ohne Angabe des generischen Parameters aufzurufen, wird Nothing abgeleitet, was für eine tatsächliche Implementierung nicht sehr nützlich ist (und das Ergebnis ist nicht nützlich). Mit der folgenden Lösung kann der NotNothing Kontext gebunden die Verwendung der Methode verhindern, ohne den erwarteten Typ anzugeben (in diesem Beispiel wird RuntimeClass ebenfalls ausgeschlossen, da ClassTags nicht Nothing , aber RuntimeClass wird abgeleitet):

@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]] = ???
}

Verwendungsbeispiel:

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow