【发布时间】:2018-09-20 07:14:23
【问题描述】:
Swift 的guard 声明非常适合提前退出。在某些情况下,除了使用return 退出之外,我们可能还想执行一个调用。
final class AppCoordinator {
func showApplePaySplash() -> Void { /* some presentation logic */ }
}
final class OnboardingCoordinator {
init(settings: Settings, parent: AppCoordinator) {
// This code should probably use a `switch` statement and not `guard`, but I am curious about this
guard settings.hasSeenApplePaySplash else {
parent.showApplePaySplash() // method returning `Void`
return
}
// Some more logic...
}
}
我很好奇的是是否可以缩短语法:
guard settings.hasSeenApplePaySplash else {
parent.showApplePaySplash()
return
}
由于这是在 init 中,我们不能写:
guard settings.hasSeenApplePaySplash else {
return parent.showApplePaySplash() // compilation error: `'nil' is the only return value permitted in an initializer`
}
我们当然可以把四行改成这个oneliner:
guard settings.hasSeenApplePaySplash else { parent.showApplePaySplash(); return }
恕我直言,读起来非常好。但我仍然想摆脱那个return(因为我很好奇它是否可能。不需要告诉我:“只使用return man”)。
在另一种情况下,我们想guard 反对一些未定义的不良行为/状态:
guard index < myArray.count else { fatalError("Array out of bounds exception, did you think about X, Y, Z?") }
我们不需要写return,因为fatalError方法返回了特定类型Never。
注意:此处以下的代码只是出于好奇而进行的实验,因为它是糟糕的 Swift 代码:
如果我们可以更改以下签名:
func showApplePaySplash() -> Void
使用Never,像这样:
func showApplePaySplash() -> Never
然后我们可以替换:
guard settings.hasSeenApplePaySplash else { parent.showApplePaySplash(); return }
这就是我很好奇的,再一次,不是首选或认可: 只需:
guard settings.hasSeenApplePaySplash else { parent.showApplePaySplash() }
但Never 没有任何初始化程序。似乎创建Never 的唯一可能性是使用诸如fatalError 之类的方法来创建崩溃。
我通过@guy-daher 找到了这个execellent SO answer - 可以替换fatalError,从而可以在测试中“捕获”它。但是它使用了waitForExpectations(timeout: 0.1),这在测试套件之外是不可能的?
所以Never 在这里可能没有帮助。 Pre Swift 4 (pre Swift 3?) 有一个名为@noreturn 的函数注释,它似乎可以提供帮助?
有什么方法可以实现吗? :)
【问题讨论】:
-
从技术上讲,您可以使用
guard提前退出,而无需使用return,而使用throw... 但我认为这并不是您想要的。不过,我不太确定您要查找的 是什么,所以 ::shrug:: -
@noreturn 是
Never的前一个。你是对的,Never在这里帮不了你,因为Never函数不会让你退出范围。 -
我看到你正在使用
Coordinator模式。我见过的大多数示例都使用start()函数。尝试将您的showApplePaySplash逻辑放在那里,并且仅使用init设置对 VC 或类似内容的引用。 -
你想要做的是一个明确的非 Swift 目标。您必须显式返回(或调用显式永远不会返回的东西)是有意的。因此,即使您想出了一些允许它的聪明方法,它也将是糟糕的 Swift。 (因为这只是好奇,不,这是不可能的,如果是的话,它可能会作为一个意外功能被删除。)请参阅常见拒绝更改列表中的“将保护重命名为除非”,它解释了必须在
guard块:github.com/apple/swift-evolution/blob/master/… -
@koen 这只是一些示例代码。我将 RxFlow 用于协调器模式,这实际上是一个“步进器”,然后我很好奇
; return是否可以被删除。