Какова цель присвоения типов в 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]] заключается в том, что мы использовали титрование в определении.

  1. Другой способ использования одного и того же определения:

    def t3 = Some(None)

    > t3: Some[None.type]

На этот раз мы явно не сказали компилятору ничего (ни это defi). И Он определил наше определение как Some [None.type]