2
我想知道是否有简单的东西,我在这里代码丢失,或者它只是一个混合的Swift技巧,阻止我做我想做的事情。无法分配到通用属性协议
我允许实现Foo
协议类型包含任何类型的entity
属性,只要它符合StringIdentifiable
:
protocol StringIdentifiable {
var id: String? { get }
}
protocol Foo: class {
associatedtype AnyStringIdentifiable: StringIdentifiable
var entity: AnyStringIdentifiable? { get set }
}
作为夫特3.1,这种“任何类型的”部分wouldn't be possible如果不使用associatedtype
。继续,假设我有另一个需要Foo
属性的协议。但是,Foo
是通用的,因此您可能知道我们不能这样做,因为“通用协议只能用作通用约束”。试图避免类型擦除一塌糊涂,我决定在我的第二个协议使用另一个associatedtype
和编译器不抱怨:
protocol Bar {
//var foo: Foo { get set } // can't do because Foo is generic
associatedtype AnyFoo: Foo
var foo: AnyFoo { get set }
}
但现在,如果我尝试设置在foo
东西,编译器会抱怨:
extension Bar {
func setEntity(_ entity: StringIdentifiable) {
foo.entity = entity
}
}
的错误是无法分配型“StringIdentifiable”到类型的值“_?”
注意:这个问题的代码是可以在操场上测试的。
哈哈听起来很hacky,但它的工作:) – Gobe
这只是类型系统帮助你!想想吧 - 对于一个给定的Bar,你知道它有一个'AnyFoo',它是一个'Foo'。 AnyFoo有一个总是一个StringIdentifiable的AnyStringIdentifiable。仅仅因为两件事都是“AnyFoo”,并不意味着它们共享相同的“AnyStringIdentifiable”。所以你从Bar'的角度来看没有足够的知识来知道你需要什么类型的'StringIdentifiable'。但是'Bar'知道它有什么类型的'Foo',并且'Foo'知道它有什么类型的'StringIdentifiable'。所以你必须这样解决它:'AnyFoo.AnyStringIdentifiable'。 –
现在我不同意......首先,任何东西都是关联类型。我不喜欢我能够在协议本身之外引用这些类型的事实。能够从Bar内部调用AnyStringIdentifiable非常奇怪。其次,我相信从酒吧的角度来看有足够的知识,Bar知道它有一些是Foo和Foos有一些是StringIdentifiable的东西。他们面前有“任何”(作为相关类型)的事实使其更加通用(尽管如果SR-522已被解决,则不需要) – Gobe