2015-02-08 31 views
5

Come posso trasferire il controllo a una linea specifica nel codice Swift?Sostituzione per istruzione goto in Swift

In Objective-C vorrei fare qualcosa di simile a quanto segue, utilizzando goto

if(a==b) 
{ 
    goto i123; 
} 
else 
{ 
    goto i456; 
} 
NSLog(@"the not reachable point"); 
i123: 
NSLog(@"line 123 is here"); 
int j = 5; 
int x = 2+j; 
i456: 
NSLog(@"line 456 is here"); 

Le uniche dichiarazioni trasferire il controllo a Swift sono riuscito a trovare erano continue, break, fallthrough, e return

continue e break funzionano solo con loop; return e fallthrough non trasferiscono il controllo in questo modo.

Cosa posso usare?

EDIT: -

risposta Julien __ 's non ha effettivamente risolvere il mio problema, ma potrebbe essere l'unica opzione disponibile al momento. quindi ho accettato la risposta di Julien__

+9

OMG. Certamente ci sono casi in cui un goto è bello. Ma generalmente il tuo codice sembra FORTRAN degli anni '50. –

+2

Ciò può facilmente causare un comportamento indefinito, ad es. se usi il valore di 'x' dopo aver saltato su' i456: '. Un obiettivo del linguaggio Swift era che il * compilatore * può verificare se tutte le variabili sono inizializzate prima di essere utilizzate. –

+1

Direi "usare le funzioni". 'goto' era in origine una soluzione alternativa per un programma senza subroutine. – Sulthan

risposta

4

Forse una dichiarazione di switch?

switch (a==b){ 
default: 
    NSLog(@"the not reachable point"); 
    fallthrough­ 
case true: 
    NSLog(@"line 123 is here"); 
    int j = 5; 
    int x = 2+j; 
    fallthrough­ 
case false: 
    NSLog(@"line 456 is here"); 
} 

MODIFICA: ecco come si potrebbe andare indietro.

let START = 0 
let STOP = -1 
var label = START 

while(label != STOP){ 
    switch (label){ 

    default: 
     label = START­ 

    case START: 
     NSLog(@"the not reachable point"); 
     if a==b { 
      label = 123 
     } else { 
      label = 456 
     } 

    case 123: 
     NSLog(@"line 123 is here"); 
     int j = 5; 
     int x = 2+j; 
     fallthrough­ 

    case 456: 
     NSLog(@"line 456 is here"); 
     fallthrough 

    case STOP: 
     label = STOP 
    } 
} 

Avvolgi il tuo codice in un'enunciazione gigante (ma ben organizzata). Potresti anche creare una funzione chiamata goto per modificare il valore dell'etichetta var.

+2

perché -1? potresti almeno dare una ragione? –

+0

in realtà il mio codice originale in obiettivo è di circa 1500 righe in cui sto usando la dichiarazione goto molto frequentemente. ho usato solo il codice nella mia domanda come esempio. btw, ho già pensato a switch. ma il problema con questo è, fallirà quando andrò avanti e indietro usando la dichiarazione goto. –

+0

IMHO questa soluzione è corretta. E lo inviterò. –

1

Che dire di questo?

var j : Int? 
var x : Int? 

if a == b { 
    println("line 123 is here") 
    j = 5 
    x = 2 + j! 
} 
println("line 456 is here") 
+0

Perché il downvote? –

+1

Probabilmente perché questo non risponde alla domanda (Come trasferire il controllo a una linea specifica?). È solo una soluzione per questo caso specifico. –

0

Sembra che Swift non voglia che qualcuno usi le istruzioni goto. Probabilmente per evitare il codice spaghetti che sarebbe troppo difficile da seguire in futuro.

Un'alternativa possibile è utilizzare le funzioni. Le funzioni hanno nomi che hanno un significato e sono più facili da capire rispetto ai semplici numeri di riga.

0

Ecco una chiusura ({...}()) approccio:

let done = false 
while !done { 
    { 
     for formantA in editedFormants { 
      for formantB in editedFormants { 
       if abs(formantA - formantB) < MIN_DISTANCE { 
        let newFormant = (formantA + formantB)/2 
        editedFormants.removeAtIndex(editedFormants.indexOf(formantA)!) 
        editedFormants.removeAtIndex(editedFormants.indexOf(formantB)!) 
        editedFormants.append(newFormant) 
        editedFormants = editedFormants.sort() 
        return 
       } 
      } 
     } 
     done = true 
    }() 
} 
0

Sono sicuro che il codice potrebbe essere riscritta per evitare l'uso di goto. In alternativa, è possibile utilizzare le funzioni all'interno delle funzioni e avere comunque accesso ai parametri esterni. Ad esempio,

func foobar(a: Int, b: Int) { 

    func i123() { 
     let j = 5 
     let x = 2+j 
     print("i123 x=\(x) b=\(b)") 
    } 

    func i456() { 
     print("i456") 
    } 

    if a == b { 
     i123() 
    } else { 
     i456() 
    } 
} 
0

Per il bene dei posteri:

  • L'articolo goto in Swift esemplifica chiaramente come implementare goto funzionalità stile, comprese le avvertenze sui perché nonusarli e una logica per la loro assenza nella lingua

  • L'autore dell'articolo lo ha reso disponibile anche come pacchetto Swift chiamato Goto.swift su GitHub.

0

Nelle lingue in cui è disponibile, non penso che GoTo sia sempre una cosa negativa. Non lo userei mai per saltare in alto, in basso e in giro all'interno di una funzione. Ciò non causa alcuna fine alla confusione. Ma mi piace usare GoTo per darmi un punto di uscita comune. Ecco un esempio di ciò che intendo (pseudo codice) qualcosa di simile:

func SomeFunction() -> Bool 
{ 
    var iReturnValue = false; 

    // Do some processing 

    if(SomeCondition == true) 
    { 
     // return true; 
     // No. Instead of having a return statement here. 
     // I'd rather goto a common exit point. 

     iReturnValue = true; 
     goto ExitPoint; 
    } 

    // Do Some More processing 

    if(SomeOtherCondition == SomeResult) 
    { 
     iReturnValue = false; 
     goto ExitPoint; 
    } 

    // 
    // More processing 
    // 

ExitPoint: 
    // By having a common exit point I can do any 
    // cleanup here and I've got a single return point 
    // which I think makes my code easier to read. 

    return iResultValue; 
} 

So che avrei potuto ottenere la stessa cosa con un paio di bretelle ben piazzato, ma ho solo trovare un Goto ben utilizzato rende la vita molto più semplice.

+0

Sembra che "guardia" sia quello che vuoi. –

+0

'guardia'? Preferirei dire "differire" ... – manicaesar

3

Ummm ..... Swift supporta effettivamente un'etichetta che può essere utilizzata come goto per il controllo del flusso ma meno flessibile. Il seguente codice è tratto da Swift il linguaggio di programmazione:

gameLoop: while square != finalSquare { 
    diceRoll += 1 
    if diceRoll == 7 { diceRoll = 1 } 

    switch square + diceRoll { 
    case finalSquare: 
    // diceRoll will move us to the final square, so the game is over 
     break gameLoop 
    case let newSquare where newSquare > finalSquare: 
    // diceRoll will move us beyond the final square, so roll again 
    continue gameLoop 
    default: 
    // this is a valid move, so find out its effect 
     square += diceRoll 
     square += board[square] 
    } 
} 
print("Game over!")