Curso
¿Te interesa aprender más sobre Scala? Haz el curso Introduction to Scala de DataCamp.
Scala es un lenguaje de programación funcional que incluye funciones como valores de primera clase y métodos, con similitudes y diferencias entre ambos. Tanto las funciones como los métodos son bloques de código reutilizable que permiten concentrar lógica repetida en un solo lugar y, mediante llamadas, ejecutar tareas concretas. También facilitan depurar y mantener el código.
Ahora bien, las funciones son objetos que se pueden asignar a una variable, mientras que los métodos se definen con la palabra clave 'def' seguida del nombre del método, la lista de parámetros y el cuerpo del método con su valor de retorno.
Declaración y definición de métodos
La sintaxis para declarar y definir métodos en Scala es la siguiente:
def 'method_name' ('parameters':'return_type_parameters') : ('return_type_of_method') = {
'method_body'
return 'value'
}
Un método en Scala se compone de las siguientes partes:
- 'def': palabra clave que se usa para declarar métodos.
- 'method_name': nombre del método, en lower camel case.
- 'parameters': parámetros del método; puede no tener ninguno o tener varios separados por comas.
- 'return_type_of_parameters': debe corresponder con el tipo de datos de la 'parameters_list' y es obligatorio.
- 'return_type_of_method': es opcional; por defecto devuelve 'Unit', aunque se puede devolver un valor con la palabra clave 'return'.
- Símbolo de asignación ('='): es opcional; si se usa, asigna el valor de retorno; si no se usa, el método no devuelve nada.
- 'method_body': bloque de código entre llaves '{}' que contiene la lógica necesaria o las operaciones a realizar.
- return: palabra clave para devolver valores y terminar la ejecución; en Scala se usa raramente.
Llamada a métodos
La sintaxis para llamar a un método en Scala es:
method_name(arguments)
La llamada se realiza con el 'method_name', el nombre del método que quieras invocar, pasando los argumentos correspondientes.
Métodos con argumentos con nombre
Los argumentos con nombre permiten pasar valores a los parámetros del método indicando explícitamente a cuál corresponde cada uno durante la llamada. A continuación tienes un ejemplo con la declaración y definición de la función y la llamada en acción:
object calculateResult {
def funSub(x:Int, y:Int) : Int =
{
var diff:Int = 0
diff = x - y
// return value
return diff
}
def main(args: Array[String]) {
// Function call
println("Difference of the value is: " + funSub(8,6));
println("Difference of the value is " + funSub(y=6,x=8));
}
}
El programa anterior produce la salida:
Difference of the value is: 2
Difference of the value is: 2
En el ejemplo hay un objeto 'calculateResult' que contiene un método 'funSub' con parámetros x e y de tipo 'Int'. El tipo de retorno del método también es 'Int' y se usa una asignación para devolver el valor. Las llaves marcan el inicio del cuerpo del método, donde la variable 'diff' se inicializa a 0. La llamada 'funSub(8,6)' en el método main empareja 8 con 'x' y 6 con 'y', realiza la resta, devuelve 'diff' y lo imprime. De forma similar, 'funSub(x=8,y=6)' empareja 6 con 'y' y 8 con 'x' sin importar el orden, realiza la misma operación y muestra el resultado.
Valores por defecto en parámetros
Puedes definir valores por defecto para los parámetros del método y omitir los argumentos en la llamada.
object calculateResult {
def funSub(x:Int=9, y:Int=6) : Int =
{
var diff:Int = 0
diff = x - y
// return value
return diff
}
def main(args: Array[String]) {
// Function call
print( "The final value is: " + funSub() );
}
}
El programa anterior produce la salida:
The final value is: 3
Como ves, el objeto 'calculateResult' incluye un método 'funSub' con parámetros x e y de tipo 'Int' y tipo de retorno 'Int'. Tras la asignación del valor de retorno, el cuerpo del método inicializa 'diff' a 0. En el main se llama a 'funSub()' sin argumentos, por lo que x toma 9 e y toma 6; se realiza la operación, se devuelve 'diff' y se imprime.
Argumentos de longitud variable
Los argumentos de longitud variable aceptan un número arbitrario de valores que el usuario puede pasar. El último parámetro del método se declara con '*' para indicar repetición.
object variableArgument {
def main(args: Array[String]) {
printAll("Scala", "is", "great")
}
def printAll(strings: String*) {
var i : Int = 0;
for( value <- strings ){
println(value);
i = i + 1;
}
}
}
El programa anterior produce la salida:
Scala
is
great
En este ejemplo, el objeto 'variableArgument' define el método 'printAll' con un argumento de longitud variable 'String*' al final. Al llamar al método puedes pasar una lista de cadenas; se itera sobre ellas y se muestran por pantalla en la función principal.
Función recursiva
La recursión es una técnica de la programación funcional en la que se resuelve un problema descomponiéndolo repetidamente en subproblemas más pequeños, similares al original. Se resuelven los subproblemas y se combinan sus soluciones para obtener la solución final. Es un enfoque de divide y vencerás que produce código limpio y elegante. Al escribir una función recursiva, hay dos puntos clave:
- Caso base: puede haber más de uno; si no se define, se puede caer en recursión infinita. Debe tener una solución directa, es decir, un resultado que no requiera recursión.
- Caso recursivo: donde se realizan las llamadas recursivas. En cada llamada el tamaño del problema debe reducirse; divide el problema en subproblemas más pequeños hasta alcanzar el caso base. Por último, combina las soluciones para resolver el problema original.
El factorial de un número n es n! y se expresa así:
Además, (n-1).(n-2)...3.2.1 es (n-1)!, por lo que el factorial siempre es n · (n-1)!
A continuación, la forma recursiva de resolverlo.
object factorialDemo {
def main(args: Array[String]) {
for (i <- 1 to 5)
println( "Factorial of " + i + ": = " + factorial(i) )
}
def factorial(n: Int): Int = {
if (n <= 1)
return 1
else
return n * factorial(n - 1)
}
}
El programa anterior produce la salida:
Factorial of 1: = 1
Factorial of 2: = 2
Factorial of 3: = 6
Factorial of 4: = 24
Factorial of 5: = 120
En el objeto 'factorialDemo', la función 'main' contiene un bucle que itera cinco veces y llama a 'factorial'. La función recursiva se invoca con n hasta alcanzar el caso base (n ≤ 1); entonces devuelve el resultado que se imprime.
Función anónima
Una función anónima es una definición ligera de función que no tiene nombre; en Scala también se conoce como function literal.
La sintaxis con ejemplos para funciones anónimas es la siguiente:
- Primera sintaxis y ejemplo:
Sintaxis:
('first_variable':'data_type', 'second_variable':'data_type') => "certain_expression"
Ejemplo:
(var1:String:var2:String) => var1 + var2
O
- Segunda sintaxis y ejemplo:
Sintaxis:
(_:'data_type')operator(_'data_type')
Ejemplo:
(_:String)+(_:String)
La primera sintaxis muestra que la expresión después de "=>" se evalúa a un valor concreto, mientras que la lista de variables antes de "=>" se usa para evaluar dicha expresión.
La segunda sintaxis funciona como un comodín: acepta el valor una sola vez como carácter 'wild card' y luego aplica el operador entre ellos.
Veamos un ejemplo de función anónima:
object anonymousDemo
{
def main(args: Array[String])
{
var function1 = (var1:Int, var2:Int) => var1 + var2
var function2 = (_:Int) + (_:Int)
// function call
println(function1(5, 5))
println(function2(7, 3))
}
}
Initializing Scala interpreter ...
Spark Web UI available at http://DESKTOP-03TH7J0:4040
SparkContext available as 'sc' (version = 2.4.3, master = local[*], app id = local-1566986265958)
SparkSession available as 'spark'
<console>:10: error: unbound placeholder parameter
var function2 = {_:Int} + {_:Int}
^
<console>:10: error: unbound placeholder parameter
var function2 = {_:Int} + {_:Int}
^
El programa anterior produce la salida:
10
10
En el objeto 'anonymousDemo', la función 'main' define dos funciones anónimas. Son sintácticamente distintas pero producen el mismo resultado: 'function1' toma los parámetros desde la llamada (5 y 5) y devuelve 10; 'function2' se invoca con 7 y 3, acepta cualquier 'Integer' válido, realiza la suma y muestra el resultado.
Conclusión
¡Enhorabuena, has terminado este tutorial!
Scala tiene muchos temas avanzados, como funciones de orden superior, funciones anidadas, currificación, etc.
Referencia:
TOUR OF SCALA BASICS
Scala | Functions – Basics
Scala - Functions
Anonymous Functions in Scala
Echa un vistazo al curso Introduction to Scala de DataCamp.