Kotlin From Scratch Paquetes y funciones básicas

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.

1. Paquetes

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..

Declaración

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.

Importaciones

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. *

Importar alias

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.

2. Funciones

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")

Funciones de una sola línea

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

Parámetros con nombre

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.

Parámetros predeterminados

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á

Interoperabilidad de Java

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.

Argumentos ilimitados

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.

Operador de propagación

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. 

Devolver múltiples valores

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): Pair require (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á:

 

Recuperando datos de 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.

Valores de retorno triple y más allá

Ahora, ¿qué pasa si quieres devolver tres valores a la vez? Kotlin nos proporciona otro tipo útil llamado Triple.

fun getUserNameStateAndAge (id: Int): Triple require (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..

Conclusión

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+!