Swift协议,其成员类型为另一个协议

时间:2018-02-04 20:51:27

标签: swift generics protocols associated-types

我尝试使用Swift协议,而且我遇到了一些有趣的事情。有很多变通方法,但任何人都可以解释下面的错误吗?

protocol UserRenderable {
    var name : String { get }
}

protocol PostRenderable {
    var title: String { get }
    var author: UserRenderable { get }
}

struct User {
    let id: String
    let name : String
}

struct Post {
    let id: String
    let title: String
    let author: User
}

extension User : UserRenderable {}

extension Post: PostRenderable {}

上面的代码(放在游乐场或其他任何地方)会引发编译错误:

  

协议要求财产'作者'使用类型' UserRenderable&#39 ;;你想添加一个存根吗?      var author:UserRenderable {get}

原因是什么?

2 个答案:

答案 0 :(得分:0)

对此最好的解决方案不是关联类型。看起来有一个更整洁的选项(来自the answer to another question):

  

没有真正的理由说明为什么这不应该是可能的,只读   属性要求可以是协变的,因为返回ConformsToB   来自属于ProtocolB的属性的实例是完全合法的。

     

斯威夫特目前不支持它。为了做到这一点,   编译器必须在协议见证之间生成一个thunk   表和符合实施,以执行必要的   类型转换(S)。例如,ConformsToB实例需要   在一个存在容器中装箱,以便输入ProtocolB   (并且调用者无法做到这一点,因为它可能不知道   关于被调用的实现的任何事情。)

     

但同样,编译器没有理由不能这样做   此

事实证明,您可以欺骗编译器进行出价,而无需使用好的typelias编写thunk。此代码编译没有问题:

protocol UserRenderable {
    var name : String { get }
}

protocol PostRenderable {
    var title: String { get }
    var author: UserRenderable { get }
}

struct User {
    let id: String
    let name : String
}

struct Post {
    let id: String
    let title: String
    let author: User
}

extension User : UserRenderable {}

extension Post: PostRenderable {
    typealias User = UserRenderable
}

答案 1 :(得分:-1)

您的Post结构具有author的非常具体的类型。该协议指定PostRenderable的内容需要具有UserRenderable的作者。虽然所有User都是UserRenderable,但并非所有UserRenderable项都是User。因此,您应该将author的类型更改为UserRenderable而不是User