Zoeken…


Lokaal type inferentie

Scala heeft een krachtig type-interferentiemechanisme ingebouwd in de taal. Dit mechanisme wordt 'Local Type Inference' genoemd:

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

De compiler kan het type variabelen afleiden uit de initialisatie-expressie. Op dezelfde manier kan het retourtype van methoden worden weggelaten, omdat ze equivalent zijn aan het type dat wordt geretourneerd door de methode. De bovenstaande voorbeelden zijn equivalent aan de onderstaande expliciete typeverklaringen:

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

Type Inferentie en Generics

De Scala-compiler kan ook typeparameters afleiden wanneer polymorfe methoden worden aangeroepen of wanneer generieke klassen worden geïnstantieerd:

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

De bovenstaande vorm van type-inferentie is vergelijkbaar met de Diamond Operator , geïntroduceerd in Java 7.

Beperkingen op inferentie

Er zijn scenario's waarin Scala-type-inferentie niet werkt. De compiler kan bijvoorbeeld het type methodeparameters niet afleiden:

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

De compiler kan het retourtype van recursieve methoden niet afleiden:

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

Voorkomen van afleiden van niets

Gebaseerd op deze blogpost .

Stel dat u een methode als deze heeft:

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

Wanneer u het probeert aan te roepen zonder de generieke parameter op te geven, wordt Nothing afgeleid, wat niet erg handig is voor een daadwerkelijke implementatie (en het resultaat is niet nuttig). Met de volgende oplossing kan de NotNothing contextbeperking het gebruik van de methode voorkomen zonder het verwachte type op te geven (in dit voorbeeld is RuntimeClass ook uitgesloten voor ClassTags niet Nothing , maar RuntimeClass wordt afgeleid):

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

Voorbeeld gebruik:

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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow