trubidata
Lección 3 de 14·14 min

Operadores

En esta guía (10)

En esta lección vas a ver cómo se nombran las cosas en Scala y cómo funcionan los operadores. La idea central es simple y muy propia del lenguaje: los operadores son métodos. 5 + 3 es, en realidad, una llamada al método + del objeto 5. Entender eso explica por qué podés usar métodos como operadores y definir operadores propios. Al final vas a aplicar todo en tres cálculos financieros: conversión de moneda, interés simple e interés compuesto.

Identificadores

Los identificadores son los nombres que les das a valores, variables, funciones, clases y demás elementos del código. Las reglas:

  • Empiezan con una letra o un guion bajo (_).
  • Después pueden tener letras, números o guiones bajos.
  • Distinguen mayúsculas de minúsculas: saldo y Saldo son dos nombres distintos.
scala
val nombre = "Juan"
val _variable = 42
val saldo2023 = 1500.0

El símbolo $ también está permitido (val $valor = 10 compila), pero está reservado para nombres que genera el compilador, así que es mejor no usarlo en tus identificadores.

Convenciones de nombres

  • Valores, variables y funciones: camelCase, la primera palabra en minúscula y las siguientes con mayúscula inicial: nombreUsuario, saldoCuenta, calcularInteres.
  • Clases y traits: PascalCase, con la primera letra en mayúscula: CuentaBancaria, Identificable.
  • Constantes: en código que viene de Java se escriben en mayúsculas con las palabras separadas por guion bajo: VALOR_PI, LIMITE_MAXIMO. La guía de estilo oficial de Scala recomienda PascalCase (ValorPi, LimiteMaximo). Vas a ver las dos; elegí una y sé consistente.
  • Paquetes: todo en minúsculas, con una estructura jerárquica: package com.miempresa.miproyecto.utilidades.

Los operadores son métodos

En Scala no hay operadores "especiales" del lenguaje para la aritmética: +, -, * y / son métodos de Int, Double y compañía. Estas dos líneas son exactamente lo mismo:

scala
val a = 5 + 3
val b = 5.+(3)
println(a == b) // true

Los operadores que más vas a usar (la lista completa está en la documentación oficial de Scala):

TipoOperadoresEjemploResultado
Aritméticos+ - * / %17 % 52
Relacionales== != > < >= <=10 >= 7true
Lógicos&& || !true && !falsetrue
A nivel de bits& | ^ ~ << >>6 & 32

Un detalle que conviene tener presente desde ahora: la división entre enteros es entera.

scala
println(7 / 2)     // 3, división entera
println(7 / 2.0)   // 3.5, alcanza con que uno sea Double
println(7 % 2)     // 1, resto
println(math.pow(2, 10)) // 1024.0, la potencia devuelve Double

No existe un operador de potencia: se usa math.pow(base, exponente), que siempre devuelve Double.

Operadores infijos

Como los operadores son métodos, también funciona al revés: cualquier método con un solo parámetro se puede usar como operador, escrito entre los dos operandos. A eso se le llama notación infija:

scala
val suma = 5 + 3                 // + es un operador infijo
val concat = "Hola" + " Mundo"   // + también, sobre String
val rango = 1 to 5               // to es un método de Int: 1.to(5)
val mayor = 10 max 25            // max también: 10.max(25)

println(rango.toList) // List(1, 2, 3, 4, 5)
println(mayor)        // 25

1 to 5 se lee casi como en lenguaje natural, y por eso es tan común en los bucles for (lección 4). Usá la notación infija para operadores simbólicos y para métodos que se leen bien así, como to, until o max. Para el resto, la notación con punto es más clara.

En Scala 3, los métodos con nombre alfabético pensados para usarse de forma infija se pueden marcar con el modificador infix (infix def max(...)). Los de la librería estándar, como to y max, se pueden usar así sin problema.

Operadores unarios

Los operadores unarios se aplican a un solo operando y van delante de él: - cambia el signo, ! niega un booleano, ~ invierte los bits.

scala
val numero = 10
val negativo = -numero    // -10
val activo = true
val inactivo = !activo    // false

Para tus propias clases, podés definir un operador unario con un método llamado unary_ seguido del símbolo. Solo se admiten cuatro: +, -, ! y ~.

scala
class MiNumero(val valor: Int) {
  def unary_- : MiNumero = new MiNumero(-valor)
  override def toString: String = s"$valor"
}

val numero = new MiNumero(5)
val opuesto = -numero   // llama a numero.unary_-
println(opuesto)        // -5

Ojo con el espacio entre unary_- y los dos puntos: si escribís unary_-:, el compilador interpreta -: como parte del nombre y da error.

Operadores de asignación

Los operadores de asignación compuesta combinan una operación con la asignación. Solo tienen sentido con var:

scala
var total = 5
total += 3   // equivale a total = total + 3, ahora vale 8
total *= 2   // equivale a total = total * 2, ahora vale 16
total -= 6   // 10
total /= 4   // 2, división entera
total %= 2   // 0
println(total)

Si venís de Java o C++: en Scala no existen ++ ni --. Para incrementar se usa contador += 1.

Precedencia

Cuando combinás operadores, Scala decide el orden según el primer carácter del operador. De mayor a menor prioridad: * / %, después + -, después :, después < >, después = !, después &, ^, |, y por último las letras (como to o max). En la práctica, se comporta como esperarías en matemática:

scala
println(2 + 3 * 4)    // 14
println((2 + 3) * 4)  // 20
println(1 + 2 to 5)   // Range 3 to 5: primero 1 + 2, después to

Ante la duda, usá paréntesis: no cuestan nada y hacen el código más fácil de leer.

Practicá

  1. Escribí una función que reciba un monto en USD o EUR, el factor de conversión entre las dos monedas y un porcentaje de impuestos. Tiene que devolver el monto en la otra moneda con los impuestos agregados.
  2. Calculadora de interés simple. Escribí una función que calcule el interés simple de un préstamo. Recibe el capital (monto del préstamo), la tasa de interés anual y el tiempo en años, y devuelve el interés total. La fórmula es Interés = Capital * Tasa * Tiempo.
  3. Interés compuesto. Escribí una función que calcule el monto total de un depósito a plazo con interés compuesto. Recibe el capital, la tasa anual y la cantidad de años, y devuelve el monto final. La fórmula es Monto = Capital * (1 + Tasa) ^ Años.

En los ejercicios 2 y 3, la tasa se expresa como fracción: 5% es 0.05.

Soluciones

scala
// Ejercicio 1
def convertirConImpuestos(monto: Double, factorConversion: Double, impuestos: Double): Double = {
  val montoEnOtraMoneda = monto * factorConversion
  val montoConImpuestos = montoEnOtraMoneda * (1 + impuestos / 100)
  montoConImpuestos
}

val montoUSD = 100.0
val factorConversionUSDaEUR = 0.85
val impuestos = 10.0

val montoConImpuestosEUR = convertirConImpuestos(montoUSD, factorConversionUSDaEUR, impuestos)
println(f"Monto en EUR con impuestos: $montoConImpuestosEUR%.2f") // 93.50

// Ejercicio 2
def calcularInteresSimple(principal: Double, tasaDeInteresAnual: Double, tiempoEnAnios: Double): Double = {
  principal * tasaDeInteresAnual * tiempoEnAnios
}

val interesSimple = calcularInteresSimple(1000.0, 0.05, 2.0)
println(s"Interés simple: $interesSimple")              // 100.0
println(s"Total a devolver: ${1000.0 + interesSimple}") // 1100.0

// Ejercicio 3
def calcularInteresCompuesto(principal: Double, tasaDeInteresAnual: Double, tiempoEnAnios: Double): Double = {
  principal * math.pow(1 + tasaDeInteresAnual, tiempoEnAnios)
}

val montoTotalCompuesto = calcularInteresCompuesto(1000.0, 0.05, 2.0)
println(s"Monto total con interés compuesto: $montoTotalCompuesto")          // 1102.5
println(calcularInteresCompuesto(10000, 0.05, 3))                            // 11576.250000000002
println(f"${calcularInteresCompuesto(10000, 0.05, 3)}%.2f")                  // 11576.25

Algunos detalles para revisar:

  • En el ejercicio 2, la consigna pide el interés, no el total. Es un error común devolver principal + interes: si querés el total, calculalo aparte, como en el último println.
  • Fijate el resultado de calcularInteresCompuesto(10000, 0.05, 3): Double no representa exactamente todos los decimales, y aparecen esos ...0002 al final. Para mostrar montos, formateá con f"...%.2f" (lo vas a ver en detalle en la lección 10). Ojo: f respeta la configuración regional de tu sistema, así que en una máquina en español puede mostrar 93,50 en lugar de 93.50. Las salidas del curso están con punto decimal. Para cálculos de dinero donde cada centavo importa, en código real se usa BigDecimal.
  • En el ejercicio 1, si declararas impuestos como Int, impuestos / 100 sería una división entera: con 10 daría 0, y el impuesto desaparecería sin aviso. Por eso conviene que los porcentajes sean Double.

Resumen

  • Los identificadores empiezan con letra o _ y distinguen mayúsculas. Usá camelCase para valores y funciones, y PascalCase para clases y traits.
  • En Scala los operadores son métodos: 5 + 3 es 5.+(3).
  • Cualquier método de un parámetro se puede usar en notación infija: 1 to 5, 10 max 25.
  • Los unarios se definen con unary_+, unary_-, unary_! o unary_~.
  • +=, -=, *=, /= y %= combinan operación y asignación; no hay ++ ni --.
  • La división entre enteros es entera, y la potencia se calcula con math.pow.

← Volver al temario