Swift 4:使用协议作为关联类型实现通用协议

3

在从Swift 3.1迁移到Swift 4代码库时,我遇到了一个问题。

当您尝试实现一个带有协议作为关联类型的闭包的通用协议方法时,问题就会出现。听起来比实际要容易:)

以下代码在Swift 3.1中可以正常运行:

protocol FooType {
    associatedtype BarType

    func foo(bar: BarType)
    func foo(action: (BarType) -> Void)
}

protocol Bar {}

class Foo: FooType {
    typealias BarType = Bar

    // Compiles in both 3.1 and 4
    func foo(bar: Bar) {
    }

    // ERROR: Candidate has non-matching type (Bar) -> Void
    func foo(action: (Bar) -> Void) {     
    }
}

但是在Swift 4中,编译器给我报错,说类Foo不符合协议FooType,而且缺少foo(action:)方法的实现。

顺便说一句,Xcode 9的"修复"功能生成了与我的实现相同的代码。

如果我使用BarType作为参数类型,则代码将会编译通过,但失去具体类型信息并不好。

2个回答

3
原来删除这行代码

会导致页面布局混乱。
typealias BarType = Bar

解决了这个问题。这是公平的 - 类型推断完成了它的工作。

然而,这应该是合法的代码,看起来像编译器中的一个错误。

已相应地报告


0
我们应该使用typealias泛型变量来为协议的associatedType提供类型。我会选择在函数中使用typealias泛型变量名称。这更有意义和合法,但我仍然不知道为什么编译器在闭包中不知道typealias参数。
class Foo: FooType {
    typealias BarType = Bar


    func foo(bar: BarType) {
     /*Code*/
    }


    func foo(action: (BarType) -> Void) {
      /*Code*/
    }
}

这是合法的。但是在这个实现中,我们失去了代码中关于我们正在处理的具体类型的清晰度。类型推断甚至可以通过不强制执行“typealias”声明来帮助我们,如果所有协议要求的实现都提供它所使用的具体类型。您可以在Apple解释中的相关类型部分进行查看。 - chezzdev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接