Métodos Mutantes en Estructuras y Enumerados en Swift

Clase 12 de 27Curso de Programación Orientada a Objetos en Swift

Resumen

En Swift, modificar propiedades dentro de estructuras y enumerados es posible y seguro con la palabra reservada mutating. Esta técnica permite que un método altere el valor de sus propias propiedades o incluso reemplace por completo el valor de self. Eso sí: solo funciona cuando el valor es variable (var); si es constante (let), el compilador lo impedirá.

Mutación en Swift: structs y enums

Las estructuras y los enumerados son tipos por valor. Al copiarse, cada copia tiene sus propios datos. Por eso, sus métodos solo pueden cambiar propiedades si están marcados como mutating. Las clases no requieren esto porque son tipos por referencia.

  • structs y enums: tipos evaluados por valor que duplican datos al copiarse.
  • mutating: habilita a un método para cambiar propiedades o reasignar self.
  • var vs let: métodos mutantes solo operan sobre valores variables.
  • self: referencia al propio valor dentro del método.

¿Qué significa mutating y cuándo usarlo?

Úsalo cuando un método de una struct o un enum necesite modificar sus propiedades o cambiar de estado. Sin mutating, el compilador bloquea la modificación aunque las propiedades sean variables.

¿Cómo se modifica una struct con moveBy?

Ejemplo con un punto que se desplaza sumando deltas a sus coordenadas:

struct Point {
    var x: Double
    var y: Double

    mutating func moveBy(deltaX: Double, deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}

var somePoint = Point(x: 4, y: 5)
somePoint.moveBy(deltaX: 2, deltaY: -3) // ahora (6, 2)
  • Si somePoint fuera let, somePoint.moveBy(...) no se podría invocar.
  • Cambiar directamente somePoint.x = 9 también exige que sea var.

¿Por qué var permite métodos mutantes y let no?

Porque let marca el valor completo como inmutable. Un método mutante cambia el valor interno; por tanto, solo puede ejecutarse sobre variables definidas con var.

Reasignación de self y propiedades calculadas

Además de modificar propiedades una a una, puedes reemplazar el valor entero del tipo reasignando self a un nuevo valor construido con las coordenadas actualizadas.

¿Cómo reasignar self para actualizar toda la estructura?

Esta variante es equivalente en efecto y a veces más clara:

struct Point {
    var x: Double
    var y: Double

    mutating func moveBy(deltaX: Double, deltaY: Double) {
        self = Point(x: self.x + deltaX, y: self.y + deltaY)
    }
}
  • Ventaja: una sola instrucción reasigna el valor completo.
  • Resultado: transparente para quien llama, mismo efecto observable.

¿Qué pasa con computed properties?

Los métodos mutantes pueden actualizar el valor almacenado del tipo y, por ende, afectar sus computed properties dependientes. La mutación se aplica al valor del tipo y a sus propiedades.

Estados mutables en enumerados

Los enums también pueden cambiar de estado con un método mutante. Un patrón común es un switch cíclico que pasa por off, low y high mediante un método next.

¿Cómo cambiar de estado con switch y next?

enum AirState {
    case off, low, high

    mutating func next() {
        switch self {
        case .off:
            self = .low
        case .low:
            self = .high
        case .high:
            self = .off
        }
    }
}

var controllerStatus = AirState.off
controllerStatus.next() // low
controllerStatus.next() // high
controllerStatus.next() // off
  • Uso de switch y case para transiciones explícitas.
  • No hace falta default cuando los cases están cubiertos.

¿Qué limitaciones existen y por qué las clases no lo requieren?

  • En enums y structs, necesitas mutating para cambiar self o sus propiedades.
  • Las clases no lo requieren: son tipos por referencia y sus métodos pueden modificar propiedades sin palabra extra.

¿Te gustaría ver más patrones con mutating, como validaciones previas o transiciones condicionadas en enums? Comparte tu caso y lo revisamos juntos.