scala static-typing ascription

¿Cuál es el propósito de las asignaciones de tipo en Scala?



static-typing ascription (5)

Inferencia de tipo: podemos omitir el nombre explícito del tipo de algo en el código fuente, llamado Inferencia de tipo (aunque se requiere en algunos casos excepcionales).

Tipo de Asignación: Ser explícito sobre el tipo de algo se llama una Asignación de Tipo. ¿Qué diferencia puede hacer?

ex: val x = 2: Byte

también vea: 1. Podemos dar vuelta explícitamente tipo a nuestras funciones

def t1 : Option[Option[String]] = Some(None) > t1: Option[Option[String]]

Otra forma de declarar esto podría ser:

def t2 = Some(None: Option[String]) > t2: Some[Option[String]]

Aquí no dimos la Option[Option[String]] devolver el tipo explícitamente y el Compilador lo dedujo como Some[Option[String]] . Por qué Some[Option[String]] se debe a que usamos la adscripción de tipo en la definición.

  1. Otra forma en que podemos usar la misma definición es:

    def t3 = Some(None)

    > t3: Some[None.type]

Esta vez No le dijimos explícitamente nada al compilador (ni esta defi). Y dedujo nuestra definición como Some [None.type]

No hay mucha información en la especificación sobre qué tipo de adscripción es, y ciertamente no hay nada allí sobre el propósito de la misma. Además de "hacer que varargs pasen", ¿para qué usaría la adscripción de tipo? A continuación se muestra algunos scala REPL para la sintaxis y los efectos de su uso.

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


La adscripción de tipos simplemente le dice al compilador qué tipo espera de una expresión, de todos los posibles tipos válidos.

Un tipo es válido si respeta las restricciones existentes, como la varianza y las declaraciones de tipo, y es uno de los tipos de expresión a la que se aplica " es un ", o hay una conversión que se aplica en el ámbito.

Entonces, java.lang.String extends java.lang.Object , por lo tanto, cualquier String es también un Object . En su ejemplo, declaró que desea que la expresión s se trate como un Object , no como una String . Como no hay restricciones que lo impidan y el tipo deseado es uno de los tipos s es a , funciona.

Ahora, ¿por qué querrías eso? Considera esto:

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)

También podría haber arreglado esto por tipo de escritura en la declaración ss , o podría haber declarado que el tipo de ss es Set[AnyRef] .

Sin embargo, las declaraciones de tipo solo logran lo mismo siempre que asigne un valor a un identificador. Lo que uno siempre puede hacer, por supuesto, si a uno no le importa tirar el código con identificadores de un solo uso. Por ejemplo, lo siguiente no compila:

def prefixesOf(s: String) = s.foldLeft(Nil) { case (head :: tail, char) => (head + char) :: head :: tail case (lst, char) => char.toString :: lst }

Pero esto hace:

def prefixesOf(s: String) = s.foldLeft(Nil: List[String]) { case (head :: tail, char) => (head + char) :: head :: tail case (lst, char) => char.toString :: lst }

Sería una tontería usar un identificador aquí en lugar de Nil . Y aunque podría simplemente escribir List[String]() , eso no siempre es una opción. Considere esto, por ejemplo:

def firstVowel(s: String) = s.foldLeft(None: Option[Char]) { case (None, char) => if ("aeiou" contains char.toLower) Some(char) else None case (vowel, _) => vowel }

Para la referencia, esto es lo que la especificación de Scala 2.7 (borrador del 15 de marzo de 2009) tiene que decir acerca de la adscripción de tipo:

Expr1 ::= ... | PostfixExpr Ascription Ascription ::= ‘:’ InfixType | ‘:’ Annotation {Annotation} | ‘:’ ‘_’ ‘*’


Puede encontrar este hilo iluminando, si es un poco complicado para seguir. Lo importante a tener en cuenta es que está agregando sugerencias de restricciones al comprobador de tipos: le da un poco más de control sobre lo que está haciendo esa fase de compilación.


Una posibilidad es cuando la red y el nivel de protocolo de serie, entonces esto:

val x = 2 : Byte

es mucho más limpio que

val x = 2.asInstanceOf[Byte]

La segunda forma también es una conversión en tiempo de ejecución (no manejada por el compilador) y podría dar lugar a algunas condiciones interesantes de exceso / defecto.


Uso la adscripción de tipo al papel sobre agujeros en la inferencia de tipo de Scala. Por ejemplo, foldLeft sobre una colección de tipo A toma un elemento inicial de tipo B y una función (B, A) => B que se usa para doblar los elementos de la colección en el elemento inicial. El valor real de tipo B se deduce del tipo del elemento inicial. Como Nil extiende List [Nothing], usarlo como elemento inicial causa problemas:

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)

Alternativamente, puede usar List.empty [Int] en lugar de Nil: List [Int].

scala> x.foldLeft(List.empty[Int])( (acc,elem) => elem::acc ) res3: List[Int] = List(4, 3, 2, 1)

editar: List.empty [A] se implementa como

override def empty[A]: List[A] = Nil

(source)

Esta es efectivamente una forma más detallada de Nil: Lista [A]