检查变量是否是Swift中的块/函数/可调用
在
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) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |