我尝试使用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}
原因是什么?
答案 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
。