2015-02-08 2 views
5

Wie kann ich die Steuerung auf eine bestimmte Linie in Swift-Code übertragen?Ersatz für goto-Anweisung in Swift

In Objective-C würde ich so etwas wie die folgenden tun, mit 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"); 

Die einzigen Steuertransfer Aussagen in Swift konnte ich finden waren continue, break, fallthrough und return

continue und break arbeiten nur mit Schleifen; return und fallthrough übertragen Sie die Kontrolle nicht auf diese Weise.

Was kann ich verwenden?

EDIT: -

Julien __ 's Antwort nicht wirklich mein Problem lösen, aber es könnte die einzige verfügbare Option im Augenblick sein. also habe ich die Antwort von Julien__ akzeptiert

+9

OMG. Natürlich gibt es Fälle, in denen ein Goto nett ist. Aber im Allgemeinen sieht dein Code wie FORTRAN aus den 50er Jahren aus. –

+2

Dies kann leicht undefiniertes Verhalten verursachen, z.B. Wenn Sie nach dem Sprung zu 'i456:' den Wert von 'x' verwenden. Ein Ziel der Swift-Sprache war, dass der * Compiler * überprüfen kann, ob alle Variablen vor der Verwendung initialisiert wurden. –

+1

Ich würde sagen "Funktionen verwenden". 'goto' war ursprünglich ein Workaround für ein Programm ohne Subroutinen. – Sulthan

Antwort

4

Vielleicht eine switch-Anweisung?

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"); 
} 

EDIT: Hier ist, wie Sie rückwärts gehen könnten.

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 
    } 
} 

Wickeln Sie Ihren Code in eine riesige (aber gut organisierte) switch-Anweisung. Sie könnten sogar eine Funktion namens goto erstellen, um den Wert der label var zu ändern.

+2

warum -1? Könntest du wenigstens einen Grund angeben? –

+0

eigentlich ist mein ursprünglicher Code in objectives ungefähr 1500 Linien lang, in denen ich goto Aussage sehr häufig benutze. Ich habe nur Code in meiner Frage als Beispiel verwendet. Übrigens, ich habe schon über den Wechsel nachgedacht. aber das Problem damit ist, es wird scheitern, wenn ich mit goto-Anweisung hin und her gehen werde. –

+0

IMHO diese Lösung ist richtig. Und ich werde es verbessern. –

1

Was ist damit?

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

Warum der Downvote? –

+1

Wahrscheinlich, weil dies die Frage nicht beantwortet (Wie kann die Kontrolle auf eine bestimmte Linie übertragen werden?). Es ist nur ein Workaround für diesen speziellen Fall. –

0

Es scheint, als ob Swift nicht möchte, dass jemand goto-Anweisungen verwendet. Wahrscheinlich um Spaghetti-Code zu vermeiden, der in Zukunft zu schwer zu folgen wäre.

Eine mögliche Alternative ist die Verwendung von Funktionen. Funktionen haben Namen, die eine Bedeutung haben und leichter zu verstehen sind als reine Zeilennummern.

0

ist hier ein Verschluss ({...}()) Ansatz:

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

Ich bin sicher, könnte Ihr Code die Verwendung von goto zu vermeiden Refactoring werden. Alternativ können Sie Funktionen innerhalb von Funktionen verwenden und trotzdem auf äußere Parameter zugreifen. Zum Beispiel

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

Aus Gründen der Nachwelt:

  • Der Artikel goto in Swift deutlich zeigt, wie goto Stil Funktionalität zu implementieren, einschließlich Warnungen auf, warum nicht, sie zu nutzen und eine Begründung für ihr Abwesenheit in der Sprache.

  • Der Artikelautor stellte es auch als Swift-Paket Goto.swift auf GitHub zur Verfügung.

0

In Sprachen, in denen es verfügbar ist glaube ich nicht, dass GoTo immer eine schlechte Sache ist. Ich würde es nie benutzen, um innerhalb einer Funktion auf und ab zu springen. Das verursacht kein Ende der Verwirrung. Aber ich benutze GoTo gerne, um mir einen gemeinsamen Ausgangspunkt zu geben. Hier ist ein Beispiel dafür, was ich meine (Pseudo-Code) so etwas wie dieses:

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; 
} 

Ich weiß, ich könnte das gleiche mit ein paar gut platzierten Klammern erreichen, aber ich finde nur ein gut genutzt Springen macht das Leben viel einfacher.

+0

Sieht aus wie "Wache" ist was du willst. –

+0

'Wache'? Ich würde eher "Defer" sagen ... – manicaesar

3

Ummm ..... Swift tatsächlich Unterstützung Label, die als Goto für den Kontrollfluss verwendet werden kann, aber weniger flexibel. Der folgende Code stammt von der Programmiersprache Swift:

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!")