En este tutorial, discutiremos acerca de la declaración y uso de las funciones infix en Kotlin, para mejorar la legibilidad de la invocación de tus funciones entre dos operandos.
El Modificador infix
La palabra reservada infix
permite llamar a una función con la notación de infijo, es decir, la capacidad de insertar la invocación de la función entre dos operandos con el fin de expresar la operación.
Esto ya lo hemos visto en la construcción básica del lenguaje Kotlin a través de los operadores aritméticos o lógicos.
Por ejemplo la función and()
, la cual evalúa a dos proposiciones:
fun main() {
val a = 20
print((a >= 0) and (a <= 21))
}
Debido a que está declarada con el modificador infix
, es posible escribirla sin la llamada regular con punto que se requiere desde el objeto de destino.
public infix fun and(other: Boolean): Boolean
Esta recibe al operando de mano derecha como parámetro y retorna un valor booleano luego de la evaluación de las proposiciones. Por ello, las siguientes expresiones son equivalentes:
a and b
// es igual a
a.and(b)
Permitiéndote omitir el punto y el paréntesis de la llamada regular de la función.
Requerimientos Al Crear Una Función infix
Para que la notación infix sea satisfecha debes cumplir las siguientes restricciones en la declaración de la función:
- Debe ser una función miembro o función de extensión
- Debe recibir un solo parámetro. Este será el operando de mano derecha de la expresión
- El parámetro no debe aceptar argumentos variables ni tener un valor por defecto
Ejemplo De Funciones infix En Kotlin
Usemos como ilustración un caso donde tengamos dos círculos en pantalla y deseemos comprobar si estos colisionan al moverse en pantalla.
La clase que representa el diseño de los círculos estaría compuesta por: radio y coordenadas del punto C(x, y) del centro.
class Circle(val radius: Float, var x: Float, var y: Float)
Ahora bien, para detectar la colisión primero calcularemos la distancia entre los centros a través de la ecuación:
d(C1,C2) = sqrt((x2-x1)2 + (y2-y1)2)
Si la distancia es menor a la suma de los radios, entonces habrá una colisión, de lo contrario la cercanía no será suficiente.
d < r1 + r2
Teniendo en cuenta lo anterior, el parámetro de entrada es de tipo Circle
y el retorno Boolean
. Usaremos las propiedades miembro del círculo recibidor (this
) y las del entrante (other
) para realizar los cálculos mencionados:
private infix fun Circle.collideWith(other: Circle): Boolean {
val dx = this.x - other.x
val dy = this.y - other.y
val distance = sqrt(dx.pow(2) + dy.pow(2))
return distance < this.radius + other.radius
}
Como ves, el resultado es una función de extensión llamada collideWidth
y la hemos marcado con el modificador infix
para que nos permita leerla de la forma «¿el circulo 1 colisiona con el circulo 2?».
Lo siguiente es simular una colisión con dos círculos de radios r1= 5
y r2=3
. Y sus centros serán C1(10,10)
y C2(8,7)
:
fun main() {
val circle1 = Circle(5f, 10f, 10f)
val circle2 = Circle(3f, 8f, 7f)
println("¿Colisión?: ${circle1 collideWith circle2}")
}
Salida:
¿Colisión?: true
Finalizando, ya te es posible crear expresiones del tipo c1 collideWith c2
para determinar en cualquier momento si dos círculos colisionan en el plano 2D.