Какова цель типовых надписей в Scala?
В спецификации не так много информации о том, что такое начертание типа, и, конечно же, там нет ничего о его назначении. За исключением того, что "заставляю прохождение varargs работать", для чего я буду использовать типовое обозначение? Ниже приведен некоторый scala REPL для синтаксиса и последствий его использования.
scala> val s = "Dave"
s: java.lang.String = Dave
scala> val p = s:Object
p: java.lang.Object = Dave
scala> p.length
<console>:7: error: value length is not a member of java.lang.Object
p.length
^
scala> p.getClass
res10: java.lang.Class[_ <: java.lang.Object] = class java.lang.String
scala> s.getClass
res11: java.lang.Class[_ <: java.lang.Object] = class java.lang.String
scala> p.asInstanceOf[String].length
res9: Int = 4
5 ответов
Тип ascription просто сообщает компилятору, какой тип вы ожидаете от выражения, от всех возможных допустимых типов.
Тип действителен, если он учитывает существующие ограничения, такие как объявления отклонений и типов, и это либо один из типов, к которым выражение, к которому он применяется, относится ктипу"is a", либо существует преобразование, которое применяется в области видимости.
Так, java.lang.String extends java.lang.Object
поэтому любой String
также Object
, В вашем примере вы объявили, что хотите выражение s
рассматриваться как Object
неString
, Поскольку нет никаких препятствий, препятствующих этому, и желаемый тип является одним из типовs
это работает.
Теперь, почему вы хотите этого? Учти это:
scala> val s = "Dave"
s: java.lang.String = Dave
scala> val p = s: Object
p: java.lang.Object = Dave
scala> val ss = scala.collection.mutable.Set(s)
ss: scala.collection.mutable.Set[java.lang.String] = Set(Dave)
scala> val ps = scala.collection.mutable.Set(p)
ps: scala.collection.mutable.Set[java.lang.Object] = Set(Dave)
scala> ss += Nil
<console>:7: error: type mismatch;
found : scala.collection.immutable.Nil.type (with underlying type object Nil)
required: java.lang.String
ss += Nil
^
scala> ps += Nil
res3: ps.type = Set(List(), Dave)
Вы также могли бы исправить это по типу ascripting s
в ss
декларация, или вы могли бы заявить ss
тип быть Set[AnyRef]
,
Однако объявления типов достигают того же самого, только если вы присваиваете значение идентификатору. Что всегда можно сделать, если, конечно, не нужно засорять код одноразовыми идентификаторами. Например, следующее не компилируется:
def prefixesOf(s: String) = s.foldLeft(Nil) {
case (head :: tail, char) => (head + char) :: head :: tail
case (lst, char) => char.toString :: lst
}
Но это делает:
def prefixesOf(s: String) = s.foldLeft(Nil: List[String]) {
case (head :: tail, char) => (head + char) :: head :: tail
case (lst, char) => char.toString :: lst
}
Было бы глупо использовать идентификатор здесь вместо Nil
, И хотя я мог бы просто написать List[String]()
напротив, это не всегда вариант. Рассмотрим это, например:
def firstVowel(s: String) = s.foldLeft(None: Option[Char]) {
case (None, char) => if ("aeiou" contains char.toLower) Some(char) else None
case (vowel, _) => vowel
}
Для справки, вот что спецификация Scala 2.7 (черновик 15 марта 2009 г.) должна сказать о типе ascription:
Expr1 ::= ...
| PostfixExpr Ascription
Ascription ::= ‘:’ InfixType
| ‘:’ Annotation {Annotation}
| ‘:’ ‘_’ ‘*’
Одна возможность, когда уровень сетевого и последовательного протоколов, то это:
val x = 2 : Byte
намного чище, чем
val x = 2.asInstanceOf[Byte]
Вторая форма также является преобразованием во время выполнения (не обрабатывается компилятором) и может привести к некоторым интересным условиям переполнения / переполнения.
Вы можете найти эту ветку осветительной, если немного усложнены. Важно отметить, что вы добавляете подсказки ограничений в средство проверки типов - это дает вам немного больше контроля над тем, что делает эта фаза компиляции.
Вывод типа: мы можем пропустить явное указание имени типа чего-либо в исходном коде, называемого выводом типа (хотя требуется в некоторых исключительных случаях).
Тип Ascription: Быть явным в отношении типа чего-либо называется Type Ascription. Какая разница это может иметь?
например: val x = 2: байт
см. также: 1. Мы можем явно указать тип возвращаемого значения для наших функций.
def t1 : Option[Option[String]] = Some(None)
> t1: Option[Option[String]]
Другой способ объявить это может быть:
def t2 = Some(None: Option[String])
> t2: Some[Option[String]]
Здесь мы не дали Option[Option[String]]
возвращаемый тип явно, и компилятор выводит его как Some[Option[String]]
, Зачем Some[Option[String]]
потому что мы использовали определение типа в определении.
Другой способ, которым мы можем использовать то же определение:
def t3 = Some(None)
> t3: Some[None.type]
На этот раз мы ничего явно не сказали компилятору (ни это определение). И это вывело наше определение как Некоторые [None.type]
Я использую типовое обозначение для бумаги над отверстиями в логическом выводе Scala. Например, foldLeft над коллекцией типа A берет начальный элемент типа B и функцию (B, A) => B, которая используется для свертывания элементов коллекции в начальный элемент. Фактическое значение типа B выводится из типа исходного элемента. Поскольку Nil расширяет List[Nothing], использование его в качестве исходного элемента вызывает проблемы:
scala> val x = List(1,2,3,4)
x: List[Int] = List(1, 2, 3, 4)
scala> x.foldLeft(Nil)( (acc,elem) => elem::acc)
<console>:9: error: type mismatch;
found : List[Int]
required: scala.collection.immutable.Nil.type
x.foldLeft(Nil)( (acc,elem) => elem::acc)
^
scala> x.foldLeft(Nil:List[Int])( (acc,elem) => elem::acc )
res2: List[Int] = List(4, 3, 2, 1)
В качестве альтернативы вы можете просто использовать List.empty[Int] вместо Nil:List[Int].
scala> x.foldLeft(List.empty[Int])( (acc,elem) => elem::acc )
res3: List[Int] = List(4, 3, 2, 1)
редактировать: List.empty[A] реализован как
override def empty[A]: List[A] = Nil
Это фактически более многословная форма Nil:List[A]