问题
I read the code block enclosed in curly braces after the keyword else
in the context of a guard-else
flow, must call a function marked with the noreturn
attribute or transfer control using return
, break
, continue
or throw
.
The last part is quite clear, while I don't understand well the first.
First of all, any function returns something (an empty tuple at least) even if you don't declare any return type. Secondly, when can we use a noreturn
function? Are the docs suggesting some core, built-in methods are marked with noreturn
?
The else clause of a guard statement is required, and must either call a function marked with the noreturn attribute or transfer program control outside the guard statement’s enclosing scope using one of the following statements:
return break continue throw
Here is the source.
回答1:
First of all, any function returns something (an empty tuple at least) even if you don't declare any return type.
(@noreturn is obsolete; see Swift 3 Update below.)
No, there are functions which terminate the process immediately
and do not return to the caller. These are marked in Swift
with @noreturn
, such as
@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)
and there may be more.
(Remark: Similar annotations exist in other programming languages
or compilers, such as [[noreturn]]
in C++11, __attribute__((noreturn))
as a GCC extension, or _Noreturn
for the
Clang compiler.)
You can mark your own function with @noreturn
if it also terminates
the process unconditionally, e.g. by calling one of the built-in functions, such as
@noreturn func myFatalError() {
// Do something else and then ...
fatalError("Something went wrong!")
}
Now you can use your function in the else clause of a guard
statement:
guard let n = Int("1234") else { myFatalError() }
@noreturn
functions can also be used to mark cases that "should not
occur" and indicate a programming error. A simple example
(an extract from 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
}
Without myFatalError()
marked as @noreturn
, the compiler would
complain about a missing return in the default case.
Update: In Swift 3 (Xcode 8 beta 6) the @noreturn
attribute
has been replaced by a Never
return type, so the above example
would now be written as
func myFatalError() -> Never {
// Do something else and then ...
fatalError("Something went wrong!")
}
回答2:
simple playground to see how it works ...
//: 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
回答3:
For instance, consider an assync operation that return either a value or error in result type. We usually write this as follows.
enum Result<Value, Error> {
case success(Value)
case failure(Error)
}
func fetch(_ request: URLRequest,
completion: (Result<(URLResponse, Data), Error>) -> Void) {
// ...
}
Now, if you know a function that always return value, never an error, then we could write :
func alwaysSucceeds(_ completion: (Result<String, Never>) -> Void) {
completion(.success("yes!"))
}
When compiler see Never, it won't force you to write all the switch cases to be exhaustive, so you can skip .failure as follows.
alwaysSucceeds { (result) in
switch result {
case .success(let string):
print(string)
}
}
Ref : https://nshipster.com/never/
来源:https://stackoverflow.com/questions/38098608/when-and-how-to-use-noreturn-attribute-in-swift