Поиск…


Локальный вывод типа

Scala имеет мощный механизм ввода-вывода, встроенный в язык. Этот механизм называется «Local Type Inference»:

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

Компилятор может вывести тип переменных из выражения инициализации. Аналогично, возвращаемый тип методов можно опустить, поскольку они эквивалентны типу, возвращаемому телом метода. Вышеприведенные примеры эквивалентны приведенным ниже объявлениям явного типа:

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

Тип вывода и дженерики

Компилятор Scala также может выводить параметры типа при вызове полиморфных методов или когда генерируются генерические классы:

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

Вышеупомянутая форма вывода типа похожа на оператора Diamond , представленную на Java 7.

Ограничения на вывод

Существуют сценарии, в которых тип-вывод Scala не работает. Например, компилятор не может вывести тип параметров метода:

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

Компилятор не может вывести возвращаемый тип рекурсивных методов:

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

Предотвращение вывода

Основано на этом сообщении в блоге .

Предположим, у вас есть такой метод:

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

Когда вы пытаетесь вызвать его без указания общего параметра, Nothing не выводится, что не очень полезно для реальной реализации (и его результат не пригодится). При следующем растворе NotNothing контекст связан можно предотвратить с помощью метода без указания ожидаемого типа (в данном примере RuntimeClass также исключаются за ClassTags не Nothing , но 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]] = ???
}

Пример использования:

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
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow