在
Swift中是否有一种简单明确的方法来检查某些东西是否是可调用的块/函数?在某些语言中,这是一件微不足道的事情,但也许我从Swift的错误角度看待这个问题?考虑以下.
func foo(){ print("foo") } var bar: () -> () = { print("bar") } var baz: () -> (Bool) = { print("baz"); return true } print(foo) // (Function) print(bar) // (Function) print(baz) // (Function) print(foo is () -> ()) // true print(bar is () -> ()) // true print(baz is () -> ()) // false print(baz is () -> (Bool)) // true
Swift知道它们都是函数,尽管没有这样的数据类型.我可以使用可靠的签名进行检查,但可能存在我不关心签名*并且只是想调用它的情况.例如:
func call(callable: () -> ()) { callable() } call(foo) // foo call(bar) // bar call(baz) // error: cannot convert value of type '() -> (Bool)' to expected argument type '() -> ()'
我可以像这样重写它,它适用于Void和Bool返回类型,但是为每种类型执行此操作都很疯狂,特别是因为我不关心它,但编译器确实……
func call(callable: Any) { if let block: () -> () = callable as? () -> () { block() } else if let block: () -> (Bool) = callable as? () -> (Bool) { block() } } call(foo) // foo call(bar) // bar call(baz) // truely baz
*同意,不关心签名是罪.为了论证,我们不关心返回类型.
解决方法
您可以检查可调用的.dynamicType的字符串表示是否存在子字符串 – >.不是超级优雅,但它有效:
func isAClosure<T>(foo: T) -> Bool { return String(foo.dynamicType).containsstring("->") } var a : () -> () = { print("Foobar") } var b : (Double) -> (Bool) = { $0 > 0 } var c : Int = 1 isAClosure(a) // true isAClosure(b) // true isAClosure(c) // false
当然,正如marcus Rossel在上面的评论中指出的那样,你仍然不会知道关于可调用的参数的任何信息(但也许这可能是下一步找出,因为你知道它是可调用的).
关于OPs问题的补充如下:仅仅是技术讨论,而不是推荐的技术.
您使用与上面相同的方法来检查函数参数是否是没有参数的闭包(() – >(…))或者既没有参数又没有返回类型(() – >()),所以上.使用这种方法,您可以定义一个泛型函数,只有当它具有某种闭包类型时才调用发送给函数的参数.对于这种“函数内调用”,您必须使用类型转换为预期的闭包类型,就像您在上面的Q中所描述的那样.这可能很难绕过这种“非通用”方法w.r.t.调用闭包.下面是一些例子.
/* Example functions */ func isAVoidParamClosure<T>(foo: T) -> Bool { let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ") return bar.count > 1 && (bar.first?.characters.count ?? 0) == 2 } func callIfVoidVoidClosure<T>(foo: T) { let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ") if bar.count > 1 && !(bar.map{ $0 == "()" }.contains(false)) { if let foo = foo as? () -> () { foo() } } } func isASingleDoubleReturnTypeClosure<T>(foo: T) -> Bool { let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ") return bar.count > 1 && bar[1] == "Double" /* rhs of '&&' lazily evaluated: [1] ok */ } func printTwoTimesResultOfVoidDoubleClosure<T>(foo: T) { if isAVoidParamClosure(foo) && isASingleDoubleReturnTypeClosure(foo) { if let foo = foo as? () -> Double { let a: Double = 2*foo() print(a) } } }
示例调用:
/* Example calls */ let a : () -> () = { print("Foobar") } let b : (Double) -> (Bool) = { $0 > 0 } let c : () -> Double = { 21.0 } let d : Int = 1 isAVoidParamClosure(a) // true isAVoidParamClosure(b) // false isAVoidParamClosure(c) // true isAVoidParamClosure(d) // false callIfVoidVoidClosure(a) // Prints "Foobar" callIfVoidVoidClosure(b) callIfVoidVoidClosure(c) callIfVoidVoidClosure(d) printTwoTimesResultOfVoidDoubleClosure(a) printTwoTimesResultOfVoidDoubleClosure(b) // Prints "42.0" printTwoTimesResultOfVoidDoubleClosure(c) printTwoTimesResultOfVoidDoubleClosure(d)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。