如何使用通用参数对函数执行“可选展开”
问题描述:
我将从小代码示例开始,尽可能简化以总结问题。如何使用通用参数对函数执行“可选展开”
比方说,我已经得到了定义如下的功能:
func doSomething<T>(using f: (String, (T) -> Void) -> Void, key: String) {
f("test", {
object in
// do something with object using key
//...
})
}
我有产生一堆汽车类与类的方法,用于为例:
class MyClass {
var prop1: String = ""
}
class MyClassAPI {
class func f1(param: String, completion: (MyClass) -> Void) {
let mc = MyClass()
mc.prop1 = "hello"
completion(mc)
}
}
然后,我在字典中有一整套键/函数夫妇:
// Any because of cast problem !
let keyFunctions: [String: Any] = [
"first" : MyClassAPI.f1,
"second" : MySecondClassAPI.f2,
"third" : MyThirdClassAPI.f3
//...
]
最后,我将遍历所有键/ f恩膏调用doSomething
:
for (k, f) in keyFunctions {
// This line doesn't work as the compiler complain about typing errors
doSomething(using: f, key: k)
}
我现在面临的问题是,我不能投我的功能,以正确的类型将它们传递给doSomething
:
的Xcode假设使用f as! (String, (_) ->()) -> Void
然后给逼投我是一个错误,_不是一种类型。
我试图用if let uf = f as? (String, (Any) -> Void) -> Void
没有机会更宽容。
我读了Swift手册的整个泛型页面,没有提示如何实现这一点。
请让我知道任何现有的方式来使用通用性执行此类事情。
答
代替Any
做出更具体的类型块
let keyFunctions: [String: (String) -> Any]
那么,至少,你可以编译和doSomething
将被调用。 但是,使其具有通用性没有意义,因为T
将始终为Any
。如果doSomething
依赖于你的类之间的共同行为,那么为所有类定义一个协议是有意义的。
如果你确实想对你的类的信息,那么你可以将非通用类将保持这个信息:
class Wrap {
var resultType: Any.Type
let f: (String) -> Any
init<T>(_ f: @escaping (String) -> T) {
self.f = f
resultType = T.self
}
}
let keyFunctions: [String: Wrap] = [
"first" : Wrap(MyClassAPI.f1),
"second" : Wrap(MySecondClassAPI.f2)
]
但resultType
不能在铸造中使用后虽然。
答
我终于做到了这种方式:
func doSomething<T>(using f: (String, (Any) -> Void, key: String, type: T.Type) -> Void, key: String) {
f("test", {
object in
guard let o as? type else { return }
// do something with o using key
//...
})
}
let keyFunctions: [String: (String, (Any) -> Void)] = [
"first" : MyClassAPI.f1,
"second" : MySecondClassAPI.f2,
"third" : MyThirdClassAPI.f3
//...
]
这些被称为高kinded类型。 Swift不支持它们。 – Alexander
字典中的函数'f1','f2'和'f3'是否返回不同的类?他们至少能遵守同样的协议吗? – Dmitry
@Dimitry不,他们不会从不同的类返回,实际上他们的参数之一是一个闭包,每一个参数都是一个不同的类型。 我想我必须让它们符合协议,谢谢 – dulgan