En Kotlin todo es un objeto en el sentido de que podemos llamar a las funciones o propiedades de cualquier variable. Algunos tipos pueden tener una representación interna especial – por ejemplo, los números, letras y booleanos pueden ser representadas como valores primitivos en tiempo de ejecución – sin embargo para el usuario se ven como clases ordinarias. En esta sección vamos a ver los tipos básicos usados en Kotlin: números (numbers), letras (chars), booleanos (booleans), matrices (arrays) y cadenas de texto (strings).
Números
Kotlin manipula los números de una forma similar a la de Java, pero no es exactamente la misma. Por ejemplo, no hay conversiones extendidas implícitas para los números, y los literales son ligeramente diferentes en algunos casos.
Kotlin proporciona los siguientes tipos de números:
Type | Bit width |
---|---|
Double | 64 |
Float | 32 |
Long | 64 |
Int | 32 |
Short | 16 |
Byte | 8 |
Las letras no son números en Kotlin.
Constantes literales
Existen los siguientes tipos de constantes literales:
- Decimales:
123
- Para indicar que es un
Long
añadiríamos la letraL
en mayúscula:123L
- Para indicar que es un
- Hexadecimales:
0x0F
- Binarios:
0b00001011
Kotlin también tiene soporte para números de coma flotante:
- Doubles por defecto:
123.5
or123.5e10
- Para los float añadiríamos
f
oF
:123.5f
Puntos en los literales numéricos
Puedes utilizar guiones bajos para facilitar la lectura de un número en Kotlin, como si estuvieses simulando puntos (o comas, en función de la región):
Representación
En la plataforma Java, los números se almacenan como tipos primitivos JVM a menos que necesitemos una referencia numérica nula (por ejemplo Int?
) o sean genéricos. En estos casos los números están encajonados.
Ten en cuenta que encajonar los números no preserva la identidad necesariamente:
Por otro lado, preserva la igualdad:
Conversiones Explícitas
Debido a las diferentes representaciones, los tipos más pequeños no son subtipos de los más grandes. Si lo fueran, habría problemas como los siguientes:
La igualdad se habría perdido por completo, sin mencionar la identidad.
Como consecuencia, los tipos más pequeños no son convertidos implicitamente a tipos más grandes. Lo cual significa que no podemos asignar un valor de tipo Byte
a una variable Int
sin una conversión explícita.
Podemos utilizar conversiones explicitas para extender los números.
Cada tipo de número soporta las siguientes convesiones:
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
ToFloat(): Float
toDouble(): Double
toChar(): Char
La ausencia de conversiones implícitas raramente se nota ya que el tipo se deduce del contexto y las operaciones aritméticas están sobrecargadas para realizar las conversiones apropiadas, por ejemplo:
Operaciones
Kotlin soporta un conjunto estándar de operaciones aritméticas sobre números, declaradas como miembros de las clases apropiadas (el compilador optimiza las llamadas a las instrucciones correspondientes).
Como operaciones bit a bit (bitwise), no hay caracteres especiales para ellas, solo fuciones con nombre que se pueden llamar de forma infija (infix), por ejemplo:
Lista completa de operaciones bit a bit (disponible solo para Int
y Long
:
shl(bits)
– signed shift left (Java’s<<
)shr(bits)
– signed shift right (Java’s>>
)ushr(bits)
– unsigned shift right (Java’s>>>
)and(bits)
– bitwise andor(bits)
– bitwise orxor(bits)
– bitwise xorinv()
– bitwise inversion
Comparación de Números de Coma Flotante
Las operaciones sobre números de coma flotante son:
- Comprobación de igualdad:
a == b
ya != b
- Operadores de comparación:
a < b
,a > b
,a <= b
,a >= b
- Comprobación de rango e instanciación de rango:
a..b
,x in a..b
,x !in a..b
Cuando los operandos a
y b
son estáticamente conocidos como Float
o Double
o sus equivalentes aceptan valores nulos (el tipo es declarado o deducido es resultado de una conversión inteligente (smart cast)), las operaciones sobre los números y el rango que forman sigue el estándar IEEE 754 de la aritmética de coma flotante.
Sin embargo, para admitir casos de usos genéricos y proporcionar ordenamiento total, cuando los operandos no se escriben de forma estática como números de coma flotante (por ejemplo Any
, Comparable<...>
, un parámetro detipo), las operaciones usan las implementaciones equals
y compareTo
para Float
y Double
, las cuales discrepan con el estándar, por lo que:
NaN
se considera igual a si mismoNaN
se considera más grande que cualquier otro elemento, incluyendoPOSITIVE_INFINITY
-0.0
se considera menor que0.0
Caracteres
Los caracteres se representan mediante el tipo Char
. No pueden ser tratados directamente como números.
Los literales de tipo carácter se escriben con comillas simples: '1'
. Los caracteres especiales se pueden escribir mediante la barra invertida. Se soportan las siguientes secuencias: \t
, \b
, \n
, \r
, \'
, \"
, \\
y \$
. Para codificar cualquier otro carácter, utiliza la sintaxis Unicode: '\uFF00
‘.
Podemos convertir explicitamente un Char
a un número Int
:
Como los números, los caracteres están encajonados (boxed) cuando se necesita una referencia que puede ser nula. La identidad no se conserva por la operación de encajonado.
Booleanos
El tipo Boolean
representa a los booleanos y tiene dos valores: true
y false
.
Los boleanos están encajonados si se necesita una referencia que puede ser nula.
Las operaciones incorporadas en los booleanos incluyen:
||
– disyunción perezosa (lazy disjunction)&&
– conjunción perezosa (lazy conjunction)!
– negación
Matrices (Arrays)
Los arrays en Kotlin se representan mediante la clase Array
, la cual tiene las funciones get
y set
(que se convierten en [] por las convenciones de sobrecarga del operador), y propiedad de tamaño, junto con algunas otras funciones miembros útiles:
Para crear un array, podemos usar la función de la biblioteca arrayOf()
y pasarle los valores, es decir, arrayOf(1, 2, 3)
crea un array [1, 2, 3]
. Alternativamente, la función arrayOfNulls()
puede ser utilizada para crear un array de un número dado lleno de elementos nulos.
Otra opción es utilizar el constructor Array
que toma el tamaño del array y la función que devuelve el valor inicial de cada elemento del array dado su índice:
Como hemos dicho antes, la operación []
representa las llamadas a las funciones get()
y set()
.
Nota: A diferencia de Java, los arrays en Kotlin son invariantes. Esto significa que kotlin no nos permite asignar un Array<String>
a un Array<Any>
, lo cual previene un posible fallo en tiempo de ejecución (pero puedes utilizar Array<out Any>
.
Kotlin también tiene clases especializadas en representar arrays de tipos primitivos: ByteArray
, ShortArray
, IntArray
, etc. Estas clases no tienen relación de herencia con la clase Array
, pero tienen el mismo conjunto de métodos y propiedades. Cada una de ellas también tiene la correspondiente función de creación:
Enteros sin firmar (Unsigned integers)
Kotlin ha introducido los siguientes tipos de enteros sin firmar:
kotlin.UByte
: un entero de 8 bit sin firmar, rango de 0 a 255kotlin.UShort
: un entero de 16 bit sin firmar, rango de 0 a 65535kotlin.UInt
: un entero de 8 bit sin firmar, rango de 0 a 2^32-1kotlin.ULong
: un entero de 8 bit sin firmar, rango de 0 a 2^64-1
Los tipos sin firmar soportan la mayoría de las operaciones de sus análogos firmados.
Los tipos sin firmar implementan otra característica, las clases en línea (inline classes).
Clases especiales
Igual que con los primitivos, cada tipo sin firmar tiene un tipo correspondiente que representa un array:
kotlin.UByteArray
kotlin.UShoprtArray
kotlin.UIntArray
kotlin.ULongArray
También tienen una API similar a la clase Array
sin sobrecarga.
Además, las progresiones y los rangos son soportados para UInt
y ULong
por las clases:
kotlin.ranges.UIntRange
kotlin.ranges.UIntProgression
kotlin.ranges.UIntProgression
kotlin.ranges.UIntProgression
Literales
Para hacer los enteros sin firmar más fáciles de utilizar, Kotlin proporciona un método para etiquetar un literal entero con un sufijo indicando el tipo sin firmar específico (similar a Float/Long):
- Los sufijos
u
yU
etiquetan al literal como sin firmar. El tipo exacto será determinado basado en el tipo esperado. Si no se proporciona tipoUInt
oULong
serán elegidos en base del tamaño del literal. - Los sufijos
uL
yUL
etiqueta de forma explicita el literal como un long sin firmar.
Strings (Cadenas de texto)
Los strings se representan por el tipo String
. Los strings son inmutables. Los elementos de un string son caracteres a los cuales se puede acceder mediante la operación de indexación: myString[i]
. Un string puede ser iterado con un bucle for:
Puedes concatenar strings con el operador +
. También funciona para concatenar strings con valores de otro tipo, mientras el valor del primer elemento en la expresión sea una string:
Recuerda que también puedes utilizar las Plantillas de Strings, algo recomendado en vez de utilizar la concatenación. Estas plantillas las verás un poco más abajo en esta página.
Literales String
Kotlin tiene dos tipos de literales string:
- Strings de escape que pueden tener caracteres de escape en ellos
- Strings en bruto que pueden contener nuevas líneas y texto arbitrario.
De esa forma podemos introducir un salto de línea. El “scaping” se consigue con una barra invertida.
Un string en bruto se delimita por una triple comilla """
, la cual no contiene ningún carácter de escape y puede contener nuevas líneas y otros caracteres:
Puedes eliminar el espacio en blanco con la función trimMargin()
.
Por defecto |
se utiliza como prefijo margen, pero puedes utilizar otro caracter y pasarle el parámetro, por ejemplo trimMargin(">")
.
Plantillas de String (String templates)
Para evitar la concatenación, puedes crear una plantilla de texto con el símbolo del dolar $myString
. Y si quieres usar sus métodos utilizarías ${myString.método}
.
Las plantillas se pueden utilizar tanto en string en bruto como en strings de escape: