是否可以在 Swift 中创建通用闭包?
Posted
技术标签:
【中文标题】是否可以在 Swift 中创建通用闭包?【英文标题】:is it possible to create a generic closure in Swift? 【发布时间】:2014-08-28 09:22:01 【问题描述】:func myfunc<T>(i:T) -> T
return i
是否可以使这个通用函数成为闭包?
let myfunc = <T>(i:T) -> T in
return i
这不起作用...
【问题讨论】:
类似(相同?)问题:***.com/questions/25401584/…. 泛型不能与闭包一起使用。 @MartinR 链接的答案提供了一种解决方法。我不认为这个问题是重复的,因为另一个问题是关于使用泛型工作的闭包,而这是一个明确的问题是否可以使用泛型。 我相信答案是这不起作用,因为它实际上没有任何意义(特别是与 Swift 无关)。myfunc
将属于抽象类型,这与尝试构造抽象类相同。我在@MartinR 链接问题的答案中讨论了更多内容。
【参考方案1】:
不,因为变量和表达式不能是通用的。只有泛型函数和泛型类型。
澄清一下:在某些语言中,您可以使用带有通用量词的类型,例如forall a. a -> a
。但是在 Swift 中,类型不能有一个通用的量词。所以表达式和值本身不能是通用的。函数声明和类型声明可以是泛型的,但是当您使用此类泛型函数或此类泛型类型的实例时,会选择某个类型(可能是实类型或类型变量)作为类型参数,然后您获得的价值本身不再是通用的。
【讨论】:
我同意 Rob 的观点,因为将typealias
与闭包一起使用来定义通用闭包类型应该是有意义的
在大多数编程语言中,泛型函数参数实际上只是函数参数,其值在编译时烘焙。因此,这意味着泛型参数的可能值在编译时进行评估,而不是仅在运行时使用(如普通函数/闭包参数)。优点是能够使用需要在编译时评估的类型参数化闭包,例如StringLiteralConvertible
。我认为您的困惑在于将变量或表达式视为通用的;相反,它是通用的闭包。
这个怎么样? typealias ResultClosure可能你需要这样的东西。
类型声明:
typealias ResultClosure<T> = (ResultCode, String?, T?) -> Void
函数声明:
func loginUser(userName: String, password: String, resultHandler: ResultClosure<TokenModel>?)
用法:
NetConnector.shared.loginUser(userName: userName ?? "", password: password ?? "") (code, message, data) in
self.display?.unlockScreen()
if code == .success
if let activeToken = data
AppData.shared.userToken = activeToken
self.display?.showHome()
else
self.display?.showError(errorMessage: message)
【讨论】:
很好,但是使用类型约束和使用该类型定义对象属性(类型别名)不起作用【参考方案3】:如前所述,Swift 中的变量不能是泛型的,因此不可能创建一个闭包,其泛型类型由调用者指定。但是,有一些解决方法:
使用SE-253,可以使任意(名义)类型可调用。因此,我们可以声明一个(非泛型)具有泛型 callAsFunction
方法的结构,而不是声明一个泛型闭包:
struct MyFunc
func callAsFunction<T>(_ i: T) -> T
return i
现在,我们可以声明一个可以使用通用值调用的非通用变量:
let myFunc = MyFunc()
let x = myFunc(42) // -> Int
let y = myFunc("foo") // -> String
请注意,此解决方法并不适用于所有情况,但在某些情况下可能会有所帮助。
【讨论】:
【参考方案4】:我找到了一些替代方法,您可以在闭包中使用 Anyobject 并将任何值传递给您的方法。
typealias genericCompletion<T:AnyObject> = ((Bool,T,String) -> Void)
struct Student
var name:String = "Kishore"
var age : String = "125"
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
self.createAGenericReturn (success, object, message) in
self.createStructGeneric (success, student, message) in
func createAGenericReturn(callback:@escaping(genericCompletion<AnyObject>))
callback(true,434.433 as AnyObject,"kishoreTest")
func createStructGeneric(callback:@escaping(genericCompletion<AnyObject>))
callback(true,Student.init() as AnyObject,"kishoreTest")
在这里你可以看到我提到了 Generic 作为 Anyobject typealias genericCompletion = ((Bool,T,String) -> Void) ,所以你可以将任何值传递给它。
【讨论】:
有趣的解决方案,利用多态性。然而,这削弱了类型检查器,如果要支持多种类型,需要实现泛型闭包的代码也必须做很多小写。以上是关于是否可以在 Swift 中创建通用闭包?的主要内容,如果未能解决你的问题,请参考以下文章
iOS Swift 如何访问在完成处理程序闭包中创建的数据——在闭包之外