加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

检查变量是否是Swift中的块/函数/可调用

发布时间:2020-12-14 04:59:44 所属栏目:百科 来源:网络整理
导读:在 Swift中是否有一种简单明确的方法来检查某些东西是否是可调用的块/函数?在某些语言中,这是一件微不足道的事情,但也许我从Swift的错误角度看待这个问题?考虑以下. func foo(){ print("foo") }var bar: () - () = { print("bar") }var baz: () - (Bool) =
在 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)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读