将成员键入为另一协议的Swift协议

将成员键入为另一协议的Swift协议,swift,generics,protocols,associated-types,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

我正在试验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”的属性“author”;是否要添加存根?
var作者:UserRenderable{get}


原因是什么?

您的
Post
结构对于
作者有一个非常特殊的类型。协议规定
可后期渲染的内容需要有
可用户渲染的作者。虽然所有的
User
s都是
UserRenderable
,但并非所有的
UserRenderable
项都是
User
。因此,您应该将
author
的类型更改为
UserRenderable
,而不是
User

最好的解决方案不是关联类型。看起来有一个更整洁的选择(来自):

没有真正的理由不可能做到这一点,只读 属性要求可以是协变的,如返回一个ConformsToB 属性类型为ProtocolB的实例是完全合法的

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

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

事实证明,你可以用好的
typelias
诱使编译器执行你的命令,而不必写一声巨响。此代码编译时没有问题:

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
}

@josh caswell,你知道为什么会这样吗?