2017-08-29 139 views
4

是否可以强制关闭完成?同样,具有返回值的函数必须总是返回,如果有办法强制关闭包含总是完成所需的语法,那么这将是ace。快速关闭 - 强制关闭始终完成

例如,该代码不会编译因为函数并不总是返回值:

func isTheEarthFlat(withUserIQ userIQ: Int) -> Bool { 
    if userIQ > 10 { 
     return false 
    } 
} 

在完全相同的方式,我想定义具有关闭功能,这如果闭包永不返回,也不会编译。例如,下面的代码可能永远不会返回completionHandler:

func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) { 
    if userIQ > 10 { 
     completionHandler(false) 
    } 
} 

上面的代码编译,但我不知道是否有是强制执行关闭在所有情况下发送完成处理程序的关键字。可能它与上述函数中的Void有关?

+1

不是一种语言的水平,虽然我的怎么可能会达到一个有趣的想法。让我尝试一些东西 – Alexander

+0

难道你不能只是在方法的最后调用完成处理程序吗? – Sweeper

+0

@Sweeper我们的大多数完成处理程序都用于服务器访问,所以它们将返回(1)发生的任何错误和(2)来自服务器的数据。由于服务器错误不是我们想向用户显示的同一错误,因此我们通常会有很多功能来决定错误是什么,同样我们也可能希望以特定方式操作从服务器返回的数据。我要求编译器确保在代码的所有分支中调用完成处理程序 - 与正常函数中返回值必须返回的方式完全相同。 – theDuncs

回答

2

不,如果您忘记(或不需要)在所有可能的条件下调用完成处理程序(如return语句),则不存在会导致编译器错误的语言构造。

这是一个有趣的想法,可能会使语言有用的增强。也许在参数声明中的某个地方使用required关键字。

+0

我一直在喝koolaid:https://stackoverflow.com/a/45945054/3141234 – Alexander

2

没有什么特别的关键字是你想要的。但你可以考虑一个有趣的方法,不会编译:

func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) { 
    let result: Bool 
    defer { 
     completionHandler(result) 
    } 
    if userIQ > 10 { 
     result = false 
    } 
} 

会做,是completionHandler被迫叫:

func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) { 
    let result: Bool 
    defer { 
     completionHandler(result) 
    } 
    if userIQ > 10 { 
     result = false 
    } else { 
     result = true 
    } 
} 

不知道这是一个很好的模式使用。

2

这是我想到的一个有趣的技术。您定义了GuarenteedExecutionGuarenteedExecutionResult类型。

A GuarenteedExecution是一个闭包的包装,它将在必须保证闭包执行的上下文中使用。

GuarenteedExecutionResult是执行GuarenteedExecution的结果。诀窍是具有所需的功能,例如isTheEarthFlat,返回GuarenteedExecutionResult。获得GuarenteedExecutionResult实例的唯一方法是在GuarenteedExecution上调用execute(argument:)。实际上,类型检查功能负责保证返回,现在正用于保证执行GuarenteedExecution

struct GuarenteedExecutionResult<R> { 
    let result: R 

    fileprivate init(result: R) { self.result = result } 
} 

struct GuarenteedExecution<A, R> { 
    typealias Closure = (A) -> R 

    let closure: Closure 

    init(ofClosure closure: @escaping Closure) { 
     self.closure = closure 
    } 

    func execute(argument: A) -> GuarenteedExecutionResult<R> { 
     let result = closure(argument) 
     return GuarenteedExecutionResult(result: result) 
    } 
} 

用法示例,在单独文件(从而无法获得GuarenteedExecutionResult.init):

let guarenteedExecutionClosure = GuarenteedExecution(ofClosure: { 
    print("This must be called!") 
}) 

func doSomething(guarenteedCallback: GuarenteedExecution<(),()>) 
    -> GuarenteedExecutionResult<()> { 
    print("Did something") 
    return guarenteedCallback.execute(argument:()) 
} 

_ = doSomething(guarenteedCallback: guarenteedExecutionClosure) 
+0

有趣的想法,与此唯一的问题是你将不得不为每个参数定义一个不同的'GuaranteedExecution'你想要的。例如如果闭包的类型是'(A,B) - > R','(A,B,C) - > R'等,那么该怎么办? – Paolo

+0

@Paolo是的,但是你可以用一个元组来代替。 A((X,Y,Z))→R)'匹配'(A) - > R',其中A是'(X,Y,Z) – Alexander