Sök…


Lokal typinferens

Scala har en kraftfull typinferensmekanism inbyggd i språket. Denna mekanism benämns "Lokal typinferens":

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

Kompilatorn kan dra slutsatsen om variabler från initialiseringsuttrycket. På liknande sätt kan returtypen av metoder utelämnas, eftersom de motsvarar den typ som returneras av metodkroppen. Ovanstående exempel motsvarar nedanstående, uttryckliga typdeklarationer:

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

Skriv inferens och generik

Scala-kompilatorn kan också härleda typparametrar när polymorfiska metoder kallas, eller när generiska klasser instanseras:

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

Ovanstående form av typinferens liknar Diamond Operator , introducerad i Java 7.

Begränsningar till slutsatser

Det finns scenarier där Scala-typinferens inte fungerar. Exempelvis kan kompilatorn inte dra slutsatsen om metodparametrarna:

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

Kompilatorn kan inte dra slutsatsen om rekursiva metoder:

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

Förhindra att sluta ingenting

Baserat på detta blogginlägg .

Antag att du har en metod som denna:

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

När du försöker ringa det utan att specificera den generiska parametern blir Nothing slutsatsen, vilket inte är särskilt användbart för en verklig implementering (och dess resultat är inte användbart). Med följande lösning kan NotNothing kontextbundet förhindra att använda metoden utan att specificera den förväntade typen (i detta exempel är RuntimeClass också uteslutet som för ClassTags inte Nothing , men RuntimeClass sluts ut):

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

Exempel på användning:

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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow