gpt4 book ai didi

swift - 检查变量是否是 Swift 中的 block /函数/可调用

转载 作者:搜寻专家 更新时间:2023-10-30 22:14:00 24 4
gpt4 key购买 nike

在 Swift 中是否有一种简单而明确的方法来检查某物是否是可调用的 block /函数?在某些语言中,这是一件微不足道的事情,但也许我在 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 '() -> ()'

我可以像这样重写它,这将适用于 VoidBool 返回类型,但对每种类型都这样做是疯狂的,尤其是因为我不在乎关于它,但是编译器确实……

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 的字符串表示是否存在子字符串 ->。不是 super 优雅,但它有效:

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 在上面的评论中指出的那样,您仍然对可调用对象的参数一无所知(但如果您知道它是可调用对象,那么下一步可能会找出答案)。


关于以下 OP 问题的补充:只是技术讨论,而不是推荐的技术。

您使用与上述相同的方法来检查函数参数是一个没有参数的闭包 (() -> (...)) 还是既没有参数也没有返回类型的闭包 (() -> ()), 等等。使用这种方法,您可以定义一个通用函数,仅当它是特定闭包类型时才调用发送给该函数的参数。对于这个“函数内调用”,您必须使用类型转换到预期的闭包类型,就像您在上面的 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)

关于swift - 检查变量是否是 Swift 中的 block /函数/可调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35046724/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com