Какова цель присвоения типов в 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
Ответы
Ответ 1
Атрибут типа просто сообщает компилятору, какой тип вы ожидаете от выражения, из всех возможных допустимых типов.
Тип является допустимым, если он соблюдает существующие ограничения, такие как объявления дисперсии и типа, и это либо один из типов, к которому выражение относится к "is a", либо к конверсии, которая применяется в области видимости.
Итак, java.lang.String extends java.lang.Object
, поэтому любой String
также является Object
. В вашем примере вы заявили, что хотите, чтобы выражение s
рассматривалось как Object
, а не String
. Поскольку нет ограничений, препятствующих этому, и желаемый тип является одним из типов s
является a, он работает.
Теперь, зачем вам это нужно? Рассмотрим это:
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 spec (март 15, проект 2009 года) должен сказать о типе присваивания:
Expr1 ::= ...
| PostfixExpr Ascription
Ascription ::= ‘:’ InfixType
| ‘:’ Annotation {Annotation}
| ‘:’ ‘_’ ‘*’
Ответ 2
Одна возможность заключается в том, что сетевые и последовательные протоколы, а затем:
val x = 2 : Byte
намного чище, чем
val x = 2.asInstanceOf[Byte]
Вторая форма также представляет собой преобразование времени выполнения (не обрабатывается компилятором) и может привести к некоторым интересным условиям перегрузки/недогрузки.
Ответ 3
Вы можете найти этот поток, освещенный, если немного свернуто, чтобы следовать. Важно отметить, что вы добавляете ограничения ограничений для проверки типов - это дает вам немного больше контроля над тем, что делает эта фаза компиляции.
Ответ 4
Я использую титровую привязку к бумаге над отверстиями в выводах типа 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)
edit: List.empty [A] реализуется как
override def empty[A]: List[A] = Nil
(источник)
Это фактически более подробная форма Nil: List [A]
Ответ 5
Вывод типа: мы можем пропустить Явное указание имени типа чего-то в исходном коде, называемое Type Inference. (Хотя это необходимо в некоторых исключительных случаях.)
Type Ascription: Явное описание типа что-то называется Type Ascription.
Какая разница?
ex: 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]
На этот раз мы явно не сказали компилятору ничего (ни это defi). И Он определил наше определение как Some [None.type]