【问题标题】:is it possible to create a generic closure in Swift?是否可以在 Swift 中创建通用闭包?
【发布时间】:2014-08-28 09:22:01
【问题描述】:
func myfunc<T>(i:T) -> T {
    return i
}

是否可以使这个通用函数成为闭包?

let myfunc = { <T>(i:T) -> T in
    return i
}

这不起作用...

【问题讨论】:

  • 类似(相同?)问题:stackoverflow.com/questions/25401584/….
  • 泛型不能与闭包一起使用。 @MartinR 链接的答案提供了一种解决方法。我不认为这个问题是重复的,因为另一个问题是关于使用泛型工作的闭包,而这是一个明确的问题是否可以使用泛型。
  • 我相信答案是这不起作用,因为它实际上没有任何意义(特别是与 Swift 无关)。 myfunc 将属于抽象类型,这与尝试构造抽象类相同。我在@MartinR 链接问题的答案中讨论了更多内容。

标签: ios generics swift closures


【解决方案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) ,所以你可以将任何值传递给它。

    【讨论】:

    • 有趣的解决方案,利用多态性。然而,这削弱了类型检查器,如果要支持多种类型,需要实现泛型闭包的代码也必须做很多小写。
    猜你喜欢
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多