Kotlin es un lenguaje de programación moderno que compila a bytecode Java. Es gratuito y de código abierto, y promete hacer que la codificación para Android sea aún más divertida.
En el artículo anterior, aprendiste sobre rangos y colecciones en Kotlin. En este tutorial, continuaremos aprendiendo el idioma observando cómo organizar el código usando paquetes, y luego continuaremos con una introducción a las funciones en Kotlin.
Si está familiarizado con Java, sabe que Java utiliza paquetes para agrupar clases relacionadas; por ejemplo, el java.util
paquete tiene una serie de clases de utilidad útiles. Los paquetes se declaran con el paquete
palabra clave, y cualquier archivo Kotlin con una paquete
La declaración al principio puede contener declaraciones de clases, funciones o interfaces..
Mirando el código de abajo, hemos declarado un paquete. com.chikekotlin.projectx
utilizando la paquete
palabra clave. Además, declaramos una clase. Mi clase
(Discutiremos las clases en Kotlin en publicaciones futuras) dentro de este paquete.
paquete com.chikekotlin.projectx clase MyClass
Ahora, el nombre completo para la clase Mi clase
es com.chikekotlin.projectx.MyClass
.
paquete com.chikekotlin.projectx divertido saySomething (): String return "¿Qué tan lejos?"
En el código anterior, creamos una función de nivel superior (llegaremos a eso en breve). Tan similar a Mi clase
, El nombre completo para la función. Di algo()
es com.chikekotlin.projectx.saySomething
.
En Kotlin, utilizamos el importar
Declaración para permitir que el compilador localice las clases, funciones, interfaces u objetos a importar. En Java, por otro lado, no podemos importar directamente funciones o clases o interfaces solo de métodos.
Usamos importar
para acceder a una función, interfaz, clase u objeto fuera del paquete donde se declaró.
import com.chikekotlin.projectx.saySomething fun main (args: Array) saySomething () // imprimirá "¿Qué tan lejos?"
En el fragmento de código anterior, importamos la función Di algo()
de un paquete diferente, y luego ejecutamos esa función.
Kotlin también soporta importaciones de comodines usando el *
operador. Esto importará todas las clases, interfaces y funciones declaradas en el paquete de una vez. Sin embargo, esto no se recomienda, por lo general, es mejor hacer sus importaciones explícitas.
importar com.chikekotlin.projectx. *
Cuando tiene bibliotecas que tienen nombres de funciones o clases en conflicto (por ejemplo, cada una declara una función con el mismo nombre), puede usar como
palabra clave para dar a esa entidad importada un nombre temporal.
importar com.chikekotlin.projectx.saySomething import com.chikekotlin.projecty.saySomething as projectYSaySomething fun main (args: Array) projectYSaySomething ()
Tenga en cuenta que el nombre temporal se usa solo dentro del archivo donde fue asignado.
Una función agrupa una serie de declaraciones de código que realizan una tarea. Los detalles de la implementación de la función están ocultos para el llamante..
En Kotlin, las funciones se definen utilizando el divertido
palabra clave, como se muestra en el siguiente ejemplo:
fun hello (name: String): String return "Hello $ name" val message = hello ("Chike") imprimir (mensaje) // imprimirá "Hello Chike"
En el código anterior, definimos una función simple. Hola()
con un solo parámetro nombre
de tipo Cuerda
. Esta función devuelve un Cuerda
tipo. El formato de definición de parámetros para funciones es nombre: tipo
, p.ej. edad: int
, precio: doble
, estudiante: StudentClass
.
fun hello (name: String): Unit print ("Hello $ name") hello ("Chike") // imprimirá "Hello Chike"
La función anterior es similar a la anterior, pero observe que esta tiene un tipo de retorno de Unidad
. Debido a que esta función no nos devuelve ningún valor significativo, simplemente imprime un mensaje; su tipo de respuesta es Unidad
por defecto. Unidad
es un objeto de Kotlin (discutiremos los objetos de Kotlin en publicaciones posteriores) que es similar a la Vacío
tipos en Java y C.
Unidad de objeto público override fun toString () = "kotlin.Unit"
Tenga en cuenta que si no declara explícitamente que el tipo de retorno sea Unidad
, El compilador deduce el tipo..
fun hello (name: String) // todavía compilará print ("Hello $ name")
Las funciones de una línea o de una línea son funciones que son solo expresiones simples. En esta función, nos deshacemos de los tirantes y utilizamos el =
Símbolo antes de la expresión. En otras palabras, nos deshacemos del bloque de función..
divertido calCircumference (radio: doble): doble return (2 * Math.PI) * radio
La función anterior se puede acortar en una sola línea:
diversión calCircumference (radio: Doble) = (2 * Math.PI) * radio
Al observar la función actualizada anterior, puede ver que hemos hecho nuestro código más conciso al eliminar las llaves. , la
regreso
palabra clave, y también el tipo de retorno (que es inferido por el compilador).
Aún puedes incluir el tipo de retorno para que sea más explícito si quieres.
diversión calCircumference (radio: doble): doble = (2 * Math.PI) * radio
Los parámetros nombrados permiten funciones más legibles al nombrar los parámetros que se pasan a una función cuando se llama.
En el siguiente ejemplo, creamos una función que imprime mi nombre completo.
fun sayMyFullName (firstName: String, lastName: String, middleName: String): Unit print ("Mi nombre completo es $ firstName $ middleName $ lastName");
Para ejecutar la función anterior, lo llamaríamos así:
sayMyFullName ("Chike", "Nnamdi", "Mgbemena")
Mirando la llamada de función arriba, no sabemos cuál Cuerda
los argumentos de tipo equivalen a los parámetros de función (aunque algunos IDE como IntelliJ IDEA pueden ayudarnos). Los usuarios de la función deberán consultar la firma de la función (o el código fuente) o la documentación para saber a qué corresponde cada parámetro..
sayMyFullName (firstName = "Chike", middleName = "Nnamdi", lastName = "Mgbemena")
En la segunda llamada de función anterior, proporcionamos los nombres de los parámetros antes de los valores de los argumentos. Puede ver que esta llamada de función es más clara y más legible que la anterior. Esta forma de llamar a las funciones ayuda a reducir la posibilidad de errores que pueden suceder cuando se intercambian argumentos del mismo tipo por error.
La persona que llama también puede alterar el orden de los parámetros usando parámetros nombrados. Por ejemplo:
sayMyFullName (lastName = "Mgbemena", middleName = "Nnamdi", firstName = "Chike") // todavía se compilará
En el código anterior, cambiamos la posición del argumento de la nombre de pila
con el apellido
. El orden de los argumentos no importa con los parámetros con nombre porque el compilador asignará cada uno de ellos al parámetro de función correcto.
En Kotlin, podemos asignar valores predeterminados a una función para cualquiera de sus parámetros. Estos valores predeterminados se utilizan si no se asigna nada a los argumentos durante la llamada a la función. Para hacer esto en Java, tendríamos que crear diferentes métodos sobrecargados.
Aquí, en nuestro calcircunferencia ()
método, modificamos el método agregando un valor predeterminado para el Pi
parámetro-Matemáticas.PI
, una constante de la java.lang.Math
paquete.
diversión calCircumference (radio: doble, pi: doble = Math.PI): doble = (2 * pi) * radio
Cuando llamamos a esta función, podemos pasar nuestro valor aproximado por Pi
o usa el predeterminado.
print (calCircumference (24.0)) // utilizó el valor predeterminado para PI e imprime 150.79644737231007 print (calCircumference (24.0, 3.14)) // pasa el valor para PI e imprime 150.72
Veamos otro ejemplo..
fun printName (firstName: String, middleName: String = "N / A", lastName: String) println ("first name: $ firstName - middle name: $ middleName - last name: $ lastName")
En el siguiente código, intentamos llamar a la función, pero no se compilará:
printName ("Chike", "Mgbemena") // no compilará
En la llamada de la función anterior, le paso mi nombre y apellido a la función y espero usar el valor predeterminado para el segundo nombre. Pero esto no compilará porque el compilador está confundido. No sabe para qué sirve el argumento "Mgbemena", es para el segundo nombre
o la apellido
parámetro?
Para resolver este problema, podemos combinar parámetros nombrados y parámetros predeterminados.
printName ("Chike", lastName = "Mgbemena") // ahora se compilará
Dado que Java no admite valores de parámetros predeterminados en los métodos, deberá especificar todos los valores de parámetros explícitamente cuando llame a una función Kotlin desde Java. Pero Kotlin nos proporciona la funcionalidad para facilitar las llamadas de Java al anotar la función de Kotlin con @JvmOverloads
. Esta anotación le indicará al compilador Kotlin que genere las funciones sobrecargadas de Java para nosotros.
En el siguiente ejemplo, anotamos el calCirumference ()
funcionar con @JvmOverloads
.
@JvmOverloads divertido calCircumference (radio: Doble, pi: Doble = Math.PI): Doble = (2 * pi) * radio
El compilador Kotlin generó el siguiente código para que las personas que llaman Java puedan elegir a cuál llamar.
// Java doble calCircumference (doble radio, doble pi); doble calCircumference (doble radio);
En la última definición de método Java generada, la Pi
el parámetro fue omitido. Esto significa que el método usará el predeterminado Pi
valor.
En Java, podemos crear un método para recibir un número no especificado de argumentos incluyendo una elipsis (...
) después de un tipo en la lista de parámetros del método. Este concepto también es compatible con las funciones de Kotlin con el uso de Vararg
modificador seguido del nombre del parámetro.
fun printInts (vararg ints: Int): Unidad para (n in ints) print ("$ n \ t") printInts (1, 2, 3, 4, 5, 6) // imprimirá 1 2 3 4 5 6
los Vararg
El modificador permite a las personas que llaman pasar una lista de argumentos separados por comas. Detrás de escena, esta lista de argumentos se incluirá en una matriz.
Cuando una función tiene múltiples parámetros, la Vararg
El parámetro suele ser el último. También es posible tener parámetros después de la Vararg
, pero necesitarás usar parámetros con nombre para especificarlos cuando llames a la función.
fun printNumbers (myDouble: Double, myFloat: Float, vararg ints: Int) println (myDouble) println (myFloat) para (n in ints) print ("$ n \ t") printNumbers (1.34, 4.4F, 2, 3, 4, 5, 6) // se compilará
Por ejemplo, en el código anterior, el parámetro con el Vararg
el modificador está en la última posición en una lista de múltiples parámetros (esto es lo que normalmente hacemos). Pero ¿y si no lo queremos en la última posición? En el siguiente ejemplo, está en la segunda posición..
fun printNumbers (myDouble: Double, vararg ints: Int, myFloat: Float) println (myDouble) println (myFloat) para (n in ints) print ("$ n \ t") printNumbers (1.34, 2, 3 , 4, 5, 6, myFloat = 4.4F) // compilará printNumbers (1.34, ints = 2, 3, 4, 5, 6, myFloat = 4.4F) // no compilará printNumbers (myDouble = 1.34, ints = 2, 3, 4, 5, 6, myFloat = 4.4F) // tampoco se compilarán
Como puede observar en el código actualizado anterior, usamos argumentos con nombre en el último parámetro para resolver esto.
Digamos que queremos pasar una matriz de enteros a nuestra números impresos ()
función. Sin embargo, la función espera que los valores se desenrollen en una lista de parámetros. Si intentas pasar la matriz directamente a números impresos ()
, verá que no se compilará.
val intsArray: IntArray = intArrayOf (1, 3, 4, 5) printNumbers (1.34, intsArray, myFloat = 4.4F) // no compilará
Para resolver este problema, necesitamos usar el operador de propagación *
. Este operador desempaquetará la matriz y luego pasará los elementos individuales como argumentos a la función para nosotros.
val intsArray: IntArray = intArrayOf (1, 3, 4, 5) printNumbers (1.34, * intsArray, myFloat = 4.4F) // ahora se compilará
Al insertar el operador de propagación *
en frente de intsArray
en la lista de argumentos de la función, el código ahora compila y produce el mismo resultado como si hubiéramos pasado los elementos de intsArray
como una lista de argumentos separados por comas.
A veces queremos devolver múltiples valores de una función. Una forma es usar el Par
escriba Kotlin para crear una Par
y luego devolverlo. Esta Par
La estructura encierra dos valores a los que luego se puede acceder. Este tipo de Kotlin puede aceptar cualquier tipo que suministre a su constructor. Y, lo que es más, los dos tipos ni siquiera tienen que ser iguales.
fun getUserNameAndState (id: Int): Pairrequire (id> 0, "Error: id es menor que 0") val userNames: Map = mapOf (101 a "Chike", 102 a "Segun", 104 a "Jane") estados de usuario val: Mapa = mapOf (101 a "Lagos", 102 a "Imo", 104 a "Enugu") val userName = userNames [id] val userState = userStates [id] return Pair (userName, userState)
En la función anterior, construimos un nuevo Par
pasando el nombre de usuario
y estado del usuario
variables como el primer y segundo argumento respectivamente a su constructor, y luego devolvió este Par
a la persona que llama.
Otra cosa a tener en cuenta es que usamos una función llamada exigir()
en el getUserNameAndState ()
función. Esta función auxiliar de la biblioteca estándar se utiliza para dar a nuestros llamadores de funciones una condición previa para cumplir, o bien una Argumento de excepción ilegal
será lanzado (discutiremos Excepciones en Kotlin en una publicación futura). El segundo argumento opcional para exigir()
es una función literal que devuelve un mensaje para que se muestre si se lanza la excepción. Por ejemplo, llamando al getUserNameAndState ()
función y paso -1
como un argumento se activará:
Par
val userNameAndStatePair: Pair= getUserNameAndState (101) println (userNameAndStatePair.first) // Chike println (userNameAndStatePair.second) // Lagos
En el código anterior, accedimos al primer y segundo valor de la Par
escriba usando su primero
y segundo
propiedades.
Sin embargo, hay una mejor manera de hacerlo: desestructurar.
val (nombre, estado) = getUserNameAndState (101) println (nombre) // Chike println (estado) // Lagos
Lo que hemos hecho en el código actualizado anterior es asignar directamente el primer y segundo valor de los valores devueltos Par
escriba a las variables nombre
y estado
respectivamente. Esta característica se llama declaración de desestructuración.
Ahora, ¿qué pasa si quieres devolver tres valores a la vez? Kotlin nos proporciona otro tipo útil llamado Triple
.
fun getUserNameStateAndAge (id: Int): Triplerequire (id> 0, "id es menor que 0") val userNames: Map = mapOf (101 a "Chike", 102 a "Segun", 104 a "Jane") estados de usuario val: Mapa = mapOf (101 a "Lagos", 102 a "Imo", 104 a "Enugu") val userName = userNames [id] val userState = userStates [id] val userAge = 6 return Triple (userNames [id], userStates [id ], userAge) val (name, state, age) = getUserNameStateAndAge (101) println (name) // Chike println (state) // Lagos println (age) // 6
Estoy seguro de que algunos de ustedes se preguntan qué hacer si desean devolver más de tres valores. La respuesta será en un post posterior, cuando discutamos las clases de datos de Kotlin..
En este tutorial, aprendió sobre los paquetes y las funciones básicas en el lenguaje de programación Kotlin. En el siguiente tutorial de la serie Kotlin From Scratch, aprenderá más sobre las funciones en Kotlin. Te veo pronto!
Para obtener más información sobre el idioma Kotlin, recomiendo visitar la documentación de Kotlin. O echa un vistazo a algunas de nuestras otras publicaciones de desarrollo de aplicaciones para Android aquí en Envato Tuts+!