是否可以在 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 -&gt; a。但是在 Swift 中,类型不能有一个通用的量词。所以表达式和值本身不能是通用的。函数声明和类型声明可以是泛型的,但是当您使用此类泛型函数或此类泛型类型的实例时,会选择某个类型(可能是实类型或类型变量)作为类型参数,然后您获得的价值本身不再是通用的。

【讨论】:

我同意 Rob 的观点,因为将 typealias 与闭包一起使用来定义通用闭包类型应该是有意义的 在大多数编程语言中,泛型函数参数实际上只是函数参数,其值在编译时烘焙。因此,这意味着泛型参数的可能值在编译时进行评估,而不是仅在运行时使用(如普通函数/闭包参数)。优点是能够使用需要在编译时评估的类型参数化闭包,例如StringLiteralConvertible。我认为您的困惑在于将变量或表达式视为通用的;相反,它是通用的闭包。 这个怎么样? typealias ResultClosure = (ResultCode, String?, T?) -> Void func loginUser(userName: String, password: String, resultHandler: ResultClosure?) 它是通用的并且有编译时类型检查 C++ 中允许变量是泛型的。【参考方案2】:

可能你需要这样的东西。

类型声明:

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 如何访问在完成处理程序闭包中创建的数据——在闭包之外

如何在 Swift iOS 中创建一个通用的弹出视图控制器

在swift中创建网页缩略图

如何从 Swift 3 中的闭包中返回

如何在 swift 中创建像 tinder 这样的堆栈视图? [关闭]

在 TableView 中创建的 7 个单元格后添加部分 - Swift