es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo puedo vincular la totalidad de un patrón a un identificador en Swift?

Recientemente estoy realizando un proyecto en Swift que involucra mucho el emparejamiento de patrones con enumeraciones que tienen otras enumeraciones o tuplas como valores asociados. Por ejemplo:

switch something {
    case .someCase(.someOtherCase(let foo, let bar)):
        // hacer algo con foo y bar...
        // Luego,
        someFunction(.someOtherCase(foo, bar))
    // otros casos...
}

Aquí hay algunas declaraciones mínimas para que el código anterior se compile:

enum Bar {
    case someOtherCase(Int, Int)
}

enum Foo {
    case someCase(Bar)
}

func someFunction(_ bar: Bar) {

}

let something = Foo.someCase(.someOtherCase(1, 1))

Lo que no me gusta de esto es que casi tengo que repetir .someCase(.someOtherCase, foo, bar) dos veces, una vez en el patrón y otra vez en la llamada a la función. Me gustaría hacer algo como esto:

// sintaxis inventada que no compila :(
case .someCase(let nested = .someOtherCase(let foo, let bar)):
    // hacer algo con foo y bar...
    // luego:
    someFunction(nested)

Esto es similar al patrón @ en Haskell.

¿Cómo puedo hacer esto?

Si esto fuera una declaración “if”, podría hacer dos emparejamientos de patrones:

if case .someCase(let nested) = something,
    case .someOtherCase(let foo, let bar) = nested {
    // hacer algo con foo y bar...
    // luego:
    someFunction(nested)
}

Pero no creo que eso funcione en un enunciado “switch”, ya que una coma en un caso de “switch” significa “o”, no “y”. Obviamente podría usar otro if case, pero eso solo hace que el código esté innecesariamente anidado. Todo el caso “switch” siendo una declaración “if” que hace otro emparejamiento de patrones también parece realmente incómodo.

Tags:  ,

Answer

  1. Avatar for davy.ai

    Desafortunadamente, no hay una forma directa de lograr esto en las declaraciones switch de Swift. Sin embargo, hay algunas soluciones alternativas que pueden ayudar a que el código sea más conciso y legible.

    Una opción es definir una función auxiliar que extraiga el valor anidado y llame a la función necesaria. Por ejemplo, podrías definir una función así:

    func manejarValorAnidado(_ anidado: Bar) {
        // hacer algo con el valor anidado...
        algunaFuncion(anidado)
    }
    

    Luego, en tu declaración switch, puedes llamar a esta función con el valor de la enumeración anidada:

    switch algo {
    case let .algunCaso(anidado):
        if case let .otroCaso(algo, barra) = anidado {
            manejarValorAnidado(anidado)
        }
        // otros casos...
    }
    

    Este enfoque separa el manejo del valor anidado de la declaración switch, lo que hace que el código sea más modular y más fácil de leer.

    Otra opción es usar una declaración guard para extraer el valor anidado y manejar el caso en el que no coincida. Por ejemplo:

    switch algo {
    case let .algunCaso(anidado):
        guard case let .otroCaso(algo, barra) = anidado else {
            // manejar el caso en el que el valor anidado no coincida...
            return
        }
        // hacer algo con algo y barra...
        algunaFuncion(anidado)
        // otros casos...
    }
    

    Este enfoque puede ayudar a evitar código anidado profundamente y hacer que la lógica de coincidencia sea más explícita. Sin embargo, no siempre es la mejor opción, ya que agrega una declaración guard adicional que podría complicar la lógica.

    En última instancia, la elección entre estos enfoques dependerá de los requisitos específicos de tu proyecto y de lo que tenga más sentido en contexto.

Comments are closed.