2016-06-29 17 views
8

ho letto il blocco di codice racchiuso tra parentesi graffe dopo la parola chiave else nel contesto di un flusso guard-else, deve chiamare una funzione contrassegnata con la noreturn attributo o trasferimento controllo utilizzando return, break, continue o throw.Quando e come utilizzare l'attributo @noreturn in Swift?

L'ultima parte è abbastanza chiara, mentre io non capisco bene la prima.

Prima di tutto, qualsiasi funzione restituisce qualcosa (una tupla vuota almeno) anche se non si dichiara alcun tipo di reso. In secondo luogo, quando è possibile utilizzare una funzione noreturn? I documenti che suggeriscono alcuni metodi di base, integrati, sono contrassegnati con noreturn?

La clausola else di un'istruzione guardia è richiesto, e deve o chiamare una funzione contrassegnata con l'attributo noreturn o programma di trasferimento controllo fuori ambito di inclusione della dichiarazione guardia utilizzando uno dei seguenti istruzioni:

return 

break 

continue 

throw 

Questo è il source.

+1

Dai un'occhiata a: http: // stack overflow.com/questions/27829132/convincing-swift-that-a-function-will-never-return-due-to-a-thrown-exception –

risposta

9

Prima di tutto, qualsiasi funzione restituisce qualcosa (una tupla vuota almeno) anche se non si dichiara alcun tipo di reso.

(@noreturn è obsoleto, vedi 3 Update Swift sotto). No, ci sono funzioni che terminano il processo immediatamente e non ritorno al chiamante. Questi sono contrassegnati in Swift con @noreturn, come

@noreturn public func fatalError(@autoclosure message:() -> String = default, file: StaticString = #file, line: UInt = #line) 
@noreturn public func preconditionFailure(@autoclosure message:() -> String = default, file: StaticString = #file, line: UInt = #line) 
@noreturn public func abort() 
@noreturn public func exit(_: Int32) 

e ci possono essere più.

(Nota: annotazioni simili esistono in altri linguaggi di programmazione o compilatori, come ad esempio [[noreturn]] in C++ 11, __attribute__((noreturn)) come estensione GCC, o _Noreturn per il compilatore Clang .)

Puoi contrassegnare la propria funzione con @noreturn se termina anche il processo incondizionatamente, es. chiamando una delle funzioni built-in, come ad esempio

@noreturn func myFatalError() { 
    // Do something else and then ... 
    fatalError("Something went wrong!") 
} 

Ora è possibile utilizzare la funzione nella clausola else di un'istruzione guard:

guard let n = Int("1234") else { myFatalError() } 

@noreturn funzioni possono anche essere usato per marcare i casi che "non dovrebbe verificarsi " e indicare un errore di programmazione.Un semplice esempio (un estratto Missing return UITableViewCell):

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell: MyTableViewCell 

    switch (indexPath.row) { 
    case 0: 
     cell = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! MyTableViewCell 
     cell.backgroundColor = UIColor.greenColor() 
    case 1: 
     cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! MyTableViewCell 
     cell.backgroundColor = UIColor.redColor() 
    default: 
     myFatalError() 
    } 
    // Setup other cell properties ... 
    return cell 
} 

Senza myFatalError() contrassegnato come @noreturn, il compilatore lamentare un ritorno mancante nel caso predefinito.


Aggiornamento: In Swift 3 (Xcode 8 beta 6) l'attributo @noreturn è stato sostituito da un tipo Never ritorno, quindi l'esempio sopra sarebbe ora essere scritto come

func myFatalError() -> Never { 
    // Do something else and then ... 
    fatalError("Something went wrong!") 
} 
+1

Esiste anche 'UIApplicationMain' che non ritorna mai (anche se non è segnato così probabilmente a causa della retrocompatibilità). Era un problema in Obj-C che chiamate come '[NSException raise]' non erano riconosciuti dal compilatore e doveva ancora esserci un 'return' dopo di loro. – Sulthan

+1

@Sulthan: Probabilmente. E non chiameresti UIApplicationMain() in una dichiarazione di guardia :) –

+0

@MartinR: so che posso usarlo per una funzione personalizzata, ho provato prima di postare :-) La mia domanda era: ha senso per uno sviluppatore avere un funzione segnata in questo modo? Stavo cercando un caso d'uso :-) –

2

semplice parco giochi per vedere come funziona ...

//: Playground - noun: a place where people can play 

import Foundation 
@noreturn func foo() { 
    print("foo") 
    exit(1) 
} 

var i: Int? 

guard let i = i else { 
    foo() 
} 

print("after foo") // this line will never executed 

//prints foo and finish 
+1

I kwow come funziona, grazie, ma quello che stavo cercando era un concreto, vero esempio in cui questo attributo può essere molto utile :-) –

+1

@IanBell quindi, si vede l'esempio ... :-). prova a immaginare che foo() pulisca prima di uscire, o persino trasferisca alcuni dati sul server o qualunque cosa tu voglia. L'attività potrebbe essere molto complessa, dipende da te. – user3441734

+0

stesso qui ... come può @noreturn (ora "Never") essere utile ... davvero, in un esempio reale ... – zumzum