Swift 协议扩展实现另一个具有共享关联类型的协议

Posted

技术标签:

【中文标题】Swift 协议扩展实现另一个具有共享关联类型的协议【英文标题】:Swift protocol extension implementing another protocol with shared associated type 【发布时间】:2015-11-28 05:35:54 【问题描述】:

考虑以下几点:

protocol Foo 
  typealias A
  func hello() -> A

protocol FooBar: Foo 
  func hi() -> A

extension FooBar 
  func hello() -> A 
    return hi()
  


class FooBarClass: FooBar 
  typealias A = String
  func hi() -> String 
    return "hello world"
  

此代码编译。但是如果我注释掉关联类型typealias A = String 的显式定义,那么由于某种原因,swiftc 无法推断出类型。

我感觉这与共享相同关联类型但没有通过类型参数化等直接断言的两个协议有关(可能关联类型不够强大/不够成熟?) ,这使得类型推断变得模棱两可。

我不确定这是否是语言的错误/不成熟,或者我在 协议扩展 中遗漏了一些细微差别,这些细微差别理所当然地导致了这种行为。

有人能解释一下吗?

【问题讨论】:

当你说swift无法推断类型时,编译器错误是什么,在哪一行? @PatrickGoley Swift 看不到 hello()hi() 的返回类型 A 是等效类型,因此,需要我另外实现 hello() 方法。它说FooBarClass 不符合协议FooBar 我认为这应该被视为一个错误。我发现的解决方法是在FooBar 协议中声明typealias。即:protocol FooBar: Foo typealias A; func hi() -> A @rintaro 抱歉,在我发送答案之前我没有看到你的注释。 【参考方案1】:

看看这个例子

protocol Foo 
    typealias A
    func hello() -> A

protocol FooBar: Foo 
    typealias B
    func hi() -> B

extension FooBar 
    func hello() -> B 
        return hi()
    


class FooBarClass: FooBar 
    //typealias A = String
    func hi() -> String 
        return "hello world"
    

使用泛型

class FooBarClass<T>: FooBar 
    var t: T?
    func hi() -> T? 
        return t
    


let fbc: FooBarClass<Int> = FooBarClass()
fbc.t = 10
fbc.hello() // 10
fbc.hi()    // 10

【讨论】:

值得一提的是,这是Swift编译器的一个bug,B可以和A同名。【参考方案2】:

为了符合所述协议,需要为协议中的关联类型提供显式值。这可以通过硬编码类型来完成,就像您对 typealias A = String 所做的那样,或者使用您提到的参数化类型,如下所示:

class FooBarClass<T>: FooBar 
    typealias A = T
    ...

Swift 不会从协议的已实现方法推断您的关联类型,因为多个方法的类型不匹配可能会产生歧义。这就是为什么必须在实现类中明确解析类型别名的原因。

【讨论】:

您能否详细说明“因为多种类型不匹配的方法可能存在歧义。”?

以上是关于Swift 协议扩展实现另一个具有共享关联类型的协议的主要内容,如果未能解决你的问题,请参考以下文章

具有最终类的多态性,可在 swift 中实现关联类型协议

Swift3 - 扩展类型集合的问题

通过框架之间的扩展实现 Swift 协议一致性

Swift中协议的简单介绍

为啥我会收到错误“协议……只能用作通用约束,因为它具有自身或关联的类型要求”?

swift protocol(协议) associatedtype关联类型