En este tutorial aprenderás a especificar paquetes en Kotlin con el objetivo de organizar estructuralmente a las declaraciones de tus programas (clases, funciones, propiedades, objetos, etc.). También verás cómo importar los elementos de dichos paquetes en diferentes archivos.
Declaración De Paquetes En Kotlin
La declaración de paquetes va en el inicio de un archivo fuente usando la sentencia package
y luego el nombre del paquete al que pertenecerá el archivo.
Por ejemplo:
Supongamos que estamos creando un videojuego inspirado en Pac Man. Ahora imaginemos que diseñamos dos archivos Kotlin, uno para simular los fantasmas enemigos y otro para ejecutar la lógica principal del juego.
Para ello separamos ambos archivos en paquetes distintos. Para el archivo de fantasmas tendremos el paquete game.ghosts
:
package game.ghosts
class Ghost() {
var x = 0
var y = 0
fun move(){
x++
y++
}
}
Y para el archivo principal el paquete game.main
:
package game.main
fun main() {
// Bucle del juego
}
La estructura de archivos sin embargo será la siguiente:
Como puedes observar, en Kotlin no es obligatorio hacer coincidir la estructura de directorios con las directivas de paquetes.
Esta convención va muy bien en proyectos de Kotlin puro, pero si tienes un proyecto con interoperabilidad entre Kotlin y Java, es mejor hacer coincidir los directorios con los paquetes.
Importaciones En Kotlin
Para importar un paquete desde un archivo Kotlin, usa la palabra clave import
seguida del nombre completo de la entidad que deseas usar en el archivo, es decir, el nombre del paquete junto a los subpaquetes necesarios para llegar al elemento.
Por ejemplo, si deseamos importar la clase Ghost
desde la función main()
, entonces usamos la directiva import
así:
package game.main
import game.ghosts.Ghost
fun main() {
val ghost1 = Ghost()
}
Importación Completamente Calificada
Otra forma de importar un elemento es usando su nombre calificado completo y omitir la sentencia import
:
fun main() {
val ghost1 = game.ghosts.Ghost()
}
Importar Todo El Contenido De Un Paquete
También es posible importar todos los elementos de un paquete usando la notación con estrella (*
):
import game.ghosts.* // Todos las entidades que tenga ghosts
Importar Enumeraciones
Ya que los enumerados por lo general contienen múltiples constantes en su interior, al usarlas se usa un acceso calificado a la clase enumeración.
Por ejemplo, si el movimiento de los fantasmas estuviese dictaminado por una enum class
para la dirección:
class Ghost() {
var x = 0
var y = 0
enum class Direction {
UP, DOWN, LEFT, RIGHT
}
fun move() {
val randomDirection = Direction.values().random()
when (randomDirection) {
Direction.UP -> ++y
Direction.DOWN -> --y
Direction.LEFT -> --x
Direction.RIGHT -> ++x
}
}
}
Podemos reemplazar el uso del nombre de Direction
por una directiva import
de la siguiente forma:
import game.ghosts.Ghost.Direction.*
El método resultaría así:
fun move() {
val randomDirection = Direction.values().random()
when (randomDirection) {
UP -> ++y
DOWN -> --y
LEFT -> --x
RIGHT -> ++x
}
}
Solucionar Conflictos De Importación
Tomemos como ejemplo de un conflicto de importación el momento en que creamos una subclase de Ghost
llamada Random
. Su propósito es crear un fantasma con una posición aleatoria en el mapa.
import kotlin.random.Random
// ...
class Random:Ghost(){
init {
x = Random.nextInt(0,300)
y = Random.nextInt(0,300)
}
}
Ahora desde main.kt
simulemos la creación simultánea de una instancia de un fantasma aleatorio y un número aleatorio con la clase Random
del SDK de Java.
package game.main
import game.ghosts.Random
fun main() {
val randomGhost = Random()
val randomNumber = kotlin.random.Random.nextInt()
}
El compilador resolverá la inspección del conflicto a través de una importación calificada completamente para la clase usada en segundo lugar.
Para evitar este comportamiento introduce un alias de importación con la palabra clave as
, luego de la directiva del import
y junto a un nombre alternativo que desambigüe la colisión de nombres.
package game.main
import kotlin.random.Random
import game.ghosts.Random as RandomGhost
fun main() {
val randomGhost = RandomGhost()
val randomNumber = Random.nextInt()
}
En este caso, hemos utilizado el alias RandomGhost
, resolviendo así el conflicto de importación entre game.ghosts.Random
y kotlin.random.Random
.