如何在 Swift 的泛型扩展中使用带有可选 class 方法的协议?

How to use a protocol with optional class methods in an extension with generic in Swift?

我正在尝试使用 class 方法对现有 class 使用扩展,例如:

@objc public protocol MyProtocol {
    optional class func foo() -> Int
}

我在扩展中使用这个协议,像这样:

extension MyClass {

    public func bar<T: MyProtocol>() {
        ...
        let x: Int = T.self.foo!() // if I do not use "self" or "!" here, I will have a compiler error
        ...
    }

这应该可以,但是当我构建它时,Xcode 说 "Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1"。如果我不在协议中使用 "optional",我就不需要在扩展中解包 foo(),即使我删除 "self" 也一切正常。谁能告诉我为什么以及如何使可选功能正常工作? 提前致谢。

您似乎在 Swift 编译器中发现了一个(相当模糊的)错误,该错误导致它崩溃。 这是一个复制品,您需要在一个文件中崩溃 swiftc:

import Foundation
@objc protocol P { optional class func f() }
func f<T: P>(t: T) { T.self.f?() }

(你不需要调用 f 它就会崩溃)

您可能应该提交雷达,因为无论您的代码如何,编译器崩溃都不是预期的行为。

如果您尝试在没有 optional 的情况下执行此操作,它会起作用(您甚至可以放弃 self)。我的猜测是泛型的实现目前没有考虑可选 class 级函数的可能性。

你可以不用像这样的泛型来做到这一点:

func f(p: MyProtocol) {
    (p as AnyObject).dynamicType.foo?()
}

(甚至可能有更好的方法,但我找不到)。

您需要 AnyObject 转换,因为如果您尝试在 p 上直接调用 .dynamicType.foo?(),您会得到 "accessing members of protocol type value 'MyProtocol.Type' is unimplemented"。如果通用版本的崩溃与此有关,我不会感到惊讶。

我还要说,值得问问自己是否真的需要一个带有可选方法(尤其是 class 级别的方法)的协议,以及是否有一种方法可以使用泛型完全静态地做你想做的事情(因为你已经在半做)。