Какова цель типа приписываний в Scala?
-
21-09-2019 - |
Вопрос
В спецификации не так много информации о том, что такое тип, и там, конечно, нет ничего об этой цели. Помимо «заставляя работать прохождение варарг», для чего я использовал тип подписания? Ниже приведена некоторая 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
Решение
Тип Ascription просто говорит компилятору, какой тип вы ожидаете от выражения, от всех возможных достоверных типов.
Тип действителен, если он уважает существующие ограничения, такие как декларации дисперсии и типа, и это либо один из типов, к которому он применяется »это", Или есть преобразование, которое применяется по объему.
Так, 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)
Вы также могли бы исправить это по типам 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 Spec (Draft 15 марта 2009 г.) говорит о типе подписания:
Expr1 ::= ...
| PostfixExpr Ascription
Ascription ::= ‘:’ InfixType
| ‘:’ Annotation {Annotation}
| ‘:’ ‘_’ ‘*’
Другие советы
Одна возможность - это когда материалы на уровне сети и серийного протокола, то это:
val x = 2 : Byte
намного чище, чем
val x = 2.asInstanceOf[Byte]
Вторая форма также представляет собой преобразование во время выполнения (не обрабатывающееся компилятором) и может привести к некоторым интересным условиям/недостаточным условиям.
Я использую тип подставки для бумаги над отверстиями в выводе типа Scala. Например, FoldLeft над коллекцией типа A принимает начальный элемент типа B и функции (B, A) => B, который используется для складывания элементов коллекции в начальный элемент. Фактическое значение типа B выводится из типа начального элемента. Поскольку NIL расширяет список [ничего], использование его в качестве начального элемента вызывает проблемы:
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] вместо нуля: 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
Это фактически более многословная форма нуля: список [a
Вы можете найти эта ветка освещение, если немного запутано, чтобы следовать. Важно отметить, что вы добавляете подсказки ограничения к проверке типа - это дает вам немного больше контроля над тем, что делает этот этап компиляции.
Вывод типа: мы можем явно пропустить имя типа чего -то в исходном коде, называемом выводом типа. (Хотя это требуется в некоторых исключительных случаях.)
Тип подписания: четко явное о типе чего -то называется типом. Какую разницу это может сделать?
Пример: 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