且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-10-16 17:59:16

看起来您已经在Swift编译器中发现了一个(相当模糊的)错误这会导致它崩溃。
下面是在单个文件中需要的所有副本的崩溃 swiftc

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

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

您应该提交一个雷达,因为无论您的代码是什么,编译器崩溃都不会发生。



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



你可以在没有泛型的情况下这样做:


$ b $
  func f(p:MyProtocol){
(p为AnyObject).dynamicType.foo?()
}

(甚至可能有更好的方法,但我无法发现它)。



您需要 AnyObject 类型转换,因为如果您尝试调用 .dynamicType.foo?() on p 直接获得访问协议类型值的成员'MyProtocol.Type'未实现。如果通用版本的崩溃与此相关,我不会感到惊讶。



我也会说它值得问自己,你是否真的需要一个协议可选的方法(特别是类级别的方法)以及是否有办法完全静态地使用泛型(因为您已经半参与)。


I am trying using extension for an existing class with class method like:

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

And I am using this protocol in an extension with generic like:

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
        ...
    }

This should work but when I build it, Xcode says "Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1". If I do not use "optional" in the protocol, I do not need to unwrap the foo() in the extension and everything works well even if I remove the "self". Can anyone tell me why and how to make the optional work properly? Thanks in advance.

It looks like you've found a (fairly obscure) bug in the Swift compiler that's causing it to crash. Here's a reproduction that's all you need in a single file to crash swiftc:

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

(you don't need to call f for it to crash)

You should probably file a radar since the compiler crashing is never expected behavior no matter what your code.

If you tried to do this without the optional, it'll work (and you can even ditch the self). My guess is the implementation of generics doesn't currently account for the possibility of optional class-level functions.

You can do it without generics like this:

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

(there may even be a better way but I can't spot it).

You need the AnyObject cast because if you try to call .dynamicType.foo?() on p directly you get "accessing members of protocol type value 'MyProtocol.Type' is unimplemented". I wouldn't be surprised if the crash of the generic version is related to this.

I'd also say that its worth asking yourself whether you really need a protocol with optional methods (especially class-level ones) and whether there's a way to do what you want entirely statically using generics (as you're already semi-doing).